---
name: new
effort: medium
description: >
  Orchestrate a team of specialized agents to implement one or more backlog cards
  end-to-end inside a dedicated worktree, with code review, doc review, QA, and
  commit for each card. Usage: /new CARD-IDS (e.g., /new FEAT-0500 FEAT-0501,
  /new CTP-0001-CTP-0008). Triggers on: /new, "implementa le card",
  "esegui le card", "lancia le card".
---

> **YOLO MODE**: All agents spawned via the Task tool MUST use `mode: "bypassPermissions"`. No exceptions.

> **SCOPE CLOSURE DISCIPLINE (BLOCKING)**: This orchestrator NEVER unilaterally defers an acceptance criterion. Silent deferral via `implementation_notes`, commit message, or final recap is a protocol violation per `framework/agents/workflows.md § Scope Closure Discipline`. Under context-window pressure, time pressure, or unforeseen complexity, the correct action is to STOP and route the decision back to the user via `AskUserQuestion` — Auto Mode's "bias toward proceeding" applies to routine decisions, NOT to scope reduction. **Phase 2.5b (AC-Closure Gate)** enforces this at the per-card level before commit and is non-skippable.

> **NO PHASE SKIP FOR PERCEIVED TIME, EVER (BLOCKING)**: MANDATORY phases are non-negotiable in BOTH sequential mode and team mode. The phrases `time budget`, `context budget`, `context pressure as override`, `for time`, `to save tokens`, `to save iterations`, or any model-invented constraint are NOT valid skip reasons. The only valid skip reasons are those explicitly enumerated in each phase's Gate table (e.g. `features.has_e2e_review: false`, backend-only diff, card type `docs`/`chore`/`config`, **the card's `review_profile`-driven review depth — see next paragraph — the `IS_TRIVIAL` fast-lane (`review_profile=skip` + non-source diff + 0 high-risk triggers), defined once in § "Trivial-card fast-lane", and the v4.7.0 Final-deferred reviews: plan-auditor grounding skipped on `/prd` holistic-audit provenance + no drift; per-card doc-review / qa-sentinel / api-perf-cost-auditor deferred to the unconditional Final FULL gate when their `review_profile`/provenance condition holds**). Documenting skipped phases at the end of a batch as `"saltati per time budget"` is a protocol violation per the FEAT-0006 incident — treat any such phrase in your own output as a self-correction trigger: stop, surface the situation via `AskUserQuestion`, and resume only after explicit user direction. Auto Mode does NOT override this. Team-mode orchestrators (L0/L1) propagate every MANDATORY phase per-card and never aggregate, reduce, or pre-filter the per-card pipeline **for any model-invented reason**.

> **REVIEW DEPTH SCALES WITH `review_profile` (deterministic — NOT a time/token skip)**: the review *depth* of a card MAY scale with its `review_profile` (the PRD-authored field, escalation-only via the Step-A detector — `light`→`full` never the reverse), exactly as the QA tier (D.4) and Codex `light`/`full` depth (D.4b / Phase 3.7 Step C) already do. This is an **enumerated, deterministic gate reason**, the polar opposite of a `time budget` skip: it is driven by a field a human authored at PRD time, not by the model's perception of how long the batch is taking. In **team mode** (since v4.18.0) every non-trivial card receives its per-card code review at the **D.4b `/codexreview`** pass: a `light` (0-trigger) card runs `/codexreview` at `profile: light` (**Codex finder + `code-reviewer` FP-gate**), a `full` card at `profile: full` (both finders). The D.2 group pass is now **doc-reviewer only** (the old D.2 group code-reviewer over light cards is removed — their code review moved to D.4b). `TRIVIAL_CARDS` (non-source diff) skip D.4b and rely on the doc-reviewer pass + the Final FULL gate. Every card still gets ≥1 per-card code review **plus** the cross-batch Final FULL gate. The **sequential** per-card pipeline is analogous (its Phase 3.7 `/codexreview` runs at `light`/`full` per the card profile). Skipping a gate WITHOUT an enumerated `review_profile`/Gate-table reason remains a protocol violation.

## Project Context

**Reads from `baldart.config.yml`:** `paths.backlog_dir`, `paths.references_dir`, `git.trunk_branch` (integration trunk; autodetected from `origin/HEAD` when the key is absent — see Phase 0 step 0), `git.merge_strategy`, `paths.high_risk_modules` (risk-detector path list), `paths.metrics` (default `docs/metrics`), `stack.language` / `stack.database` / `stack.deployment` / `stack.schema_deploy_from_trunk_only` (gate guards), and `features.has_e2e_review` / `features.has_design_system` / `features.has_lsp_layer` / `features.has_code_graph`.
**Gated by features:** `features.has_backlog` (skill REFUSES to run when `false` — this orchestrator operates on backlog cards by definition).
**Overlay:** loads `.baldart/overlays/new.md` if present — project-specific canonical-docs registry (e.g. ssot-registry, linking-protocol guides), tooling paths (e.g. validation scripts).
**On missing/empty keys:** ask the user; do not assume defaults. See `framework/agents/project-context.md` § 3.

You are the **backlog orchestrator**. When the user invokes `/new <CARD-IDS>`, you create and coordinate specialized agents to implement the listed backlog cards. You NEVER write production code yourself — you only orchestrate.

Parse the card IDs from the arguments. Cards can be specified as:
- Space-separated: `GLOB-001 GLOB-002 GLOB-003`
- Hyphen-range: `GLOB-001-GLOB-008` (expands to all cards in range)
- Comma-separated: `GLOB-001, GLOB-002, GLOB-003`
- **Epic expansion (`-full` / `--full`)**: `/new <PARENT-ID> -full` (e.g., `/new FEAT-005 -full`) expands to ALL children of the parent epic with **NO questions asked**. Children discovery — union of two rules:
  1. YAML files in `${paths.backlog_dir}` whose filename starts with `<PARENT-ID>-` (matches `FEAT-005-1.yml`, `FEAT-005-2.yml`, …; never matches `FEAT-005.yml` itself, never matches `FEAT-0050.yml` because the separator is a literal dash).
  2. Cards in `${paths.backlog_dir}` whose `group.parent` YAML field equals `<PARENT-ID>` (catches children that don't follow the prefix convention).

  The parent epic card itself is **excluded** (epic parents are typically planning containers; to include it, list it explicitly: `/new FEAT-005 FEAT-005 -full`). Children are sorted by `group.sequence` ASC, falling back to lexicographic ID order. The flag is **batch-scoped**: `/new FEAT-005 FEAT-008 -full` expands BOTH parents. If a `-full` parent has zero discovered children → HALT and report (do not silently no-op). With `-full`, all children share the same `group.parent`, so the existing worktree-grouping logic (pre-flight step 4) places them in ONE worktree under the parent's `git_strategy.branch` — no grouping question is asked.

  Parser contract: strip `-full` / `--full` tokens from the args list, treat each remaining token as a parent ID, and expand via the rules above. Mixed batches are allowed (`/new FEAT-005 -full FEAT-007` queues all children of FEAT-005 PLUS the standalone FEAT-007).

If no card IDs are provided, ask the user which cards to implement.

**Opt-in session telemetry (`-stats` / `--stats`)**: strip `-stats` / `--stats` from the args list exactly like `-full` (it is NOT a card ID), and set an internal flag `STATS=true` for this run. When present, Phase 8 additionally measures REAL token + wall-clock cost per agent role (coder, code-reviewer, …) by post-processing the session transcripts — zero model-token overhead, runs in Bash after the work is done. When absent, Phase 8 behaves exactly as before. The flag is batch-scoped and composes with `-full` (`/new FEAT-005 -full -stats`).

## Effort

**Baseline:** `effort: medium` (frontmatter). **Inline override:** pass
`effort=<low|medium|high|xhigh|max>` anywhere in the invocation to scale
reasoning depth for this run — detect it once at kickoff and strip the token
before consuming user input. Level→behavior mapping, parsing contract, and
precedence caveats: `framework/agents/effort-protocol.md`.


---

## Context Tracking (CRITICAL)

You MUST maintain a **persistent tracking file** at `/tmp/batch-tracker-<FIRST-CARD-ID>.md` throughout the entire batch run (e.g., `/tmp/batch-tracker-FEAT-0396.md`). Use the **first card ID** from the batch as the suffix. This ensures multiple `/new` sessions running in parallel terminals (e.g., one per worktree) do NOT conflict.

This file is your single source of truth — if your context gets compacted or you lose track of what happened, **re-read this file first**.

### Tracking file format

At batch start — **before Phase 0 runs** (Phase 0 step 1 writes to the `## Worktree` section and Phase 0 step 5 writes the phase log, so the file MUST already exist) — create `/tmp/batch-tracker-<FIRST-CARD-ID>.md` with:

```markdown
# Batch Run: [CARD-IDS]
<!-- MANDATORY phases are non-skippable in BOTH sequential and team mode.
     Inventing reasons ("time budget", "context pressure", "out of scope of this card")
     to skip phases or defer ACs is a protocol violation. See FEAT-0006 incident.
     Only the user, via AskUserQuestion, can approve a deferral. -->
Started: [timestamp]
Total cards: [N]

## Workspace Snapshot
(none — Phase 0 will populate if the main repo had uncommitted work; the stash entry, when present, is recorded by its MESSAGE label, never a positional `stash@{N}`)

## Worktree
Branch: [feat/FEAT-XXXX-slug]
Slug: [the slug used to derive Branch/Path — see Pre-flight step 4]
Path: [.worktrees/feat-FEAT-XXXX-slug]
Port: [from registry]
Created: [ISO-8601 timestamp the worktree was created — Pre-flight step 6c backfills from the worktree-setup subagent's created_at; Phase 8 cycle_time_mins start anchor]
Group parent: [FEAT-XXXX or "standalone"]
Main repo: [/absolute/path/to/main/repo]
Trunk branch: [resolved git.trunk_branch — Phase 0 step 0 populates]

## Card Queue
- [ ] CARD-001 — [title from backlog]
- [ ] CARD-002 — [title from backlog]
...

## Completed Cards
(none yet)

## Current Card
(none — starting pre-flight)

## File Ownership Map
(built during pre-flight — one entry per agent)
| File | Assigned Agent (Card ID) |
|------|--------------------------|

## Cross-Card Conflicts (Codex)
(pending — for batches > 1 card; may be SKIPPED if the batch was already audited jointly by /prd Step 6.6 with no drift since — see Step 3d skip decision)

## Issues & Flags
(none yet)

## Lessons Learned
(none yet)
<!-- Format: "PHASE: pattern — file" e.g. "SIMPLIFY: use formatCurrency util — src/lib/utils.ts" -->
```

### Update rules

- **Before starting a card**: move it to `## Current Card` with phase info, and record `phase_module_loaded: <modulo>` as you Read each phase module (per § "Routing" HARD RULE) so context recovery can re-load it.
- **After each phase**: update the current card's phase status in the tracker.
- **After completing a card**: move it from `Current Card` to `## Completed Cards` with:
  - Commit hash
  - One-line summary of what was implemented
  - Any flags/issues found
  - Doc review result (pass/fail + what was added)
  - Test results (new + existing count, pass/fail)
  - Fix cycles count
  - UX testing result (PASS/FAIL/SKIP + test file path if written)
  - QA result (profile used: skip/light/balanced/deep | verdict: PASS/FAIL/SKIP | confidence % | failing gates: which of lint/tsc/test/build/markdownlint, or "none")
  - QA findings file (e.g. `/qa/FEAT-XXXX.md` or "skipped")
  - **card_status: DONE (verified)** — confirms the backlog YAML was updated and re-read to verify
- **When blocked**: log the blocker in `## Issues & Flags`.
- **On context recovery**: if you ever feel lost or after context compaction, IMMEDIATELY read your tracker file (`/tmp/batch-tracker-<FIRST-CARD-ID>.md`) to restore your state.
- **Mirror every transition to the user (MANDATORY)**: this tracker file is internal — the user does NOT see it. Every transition you log here MUST also be reflected in the **two user-visible surfaces** defined in § "Progress Visibility": the native **Task spine** (TaskUpdate) and, at transition boundaries, the **Progress Bar**. The tracker is the recovery SSOT; the Task spine + Progress Bar are its live mirror.

---

## Progress Visibility (MANDATORY)

The `/tmp/batch-tracker-*.md` file is your **internal** recovery SSOT — the user never sees it. Because `/new` runs largely autonomously (YOLO mode, long stretches of agent spawns), the user otherwise has no idea which phase is running, which wave of the team mode is in flight, or which gate was just resolved vs skipped. This section defines the **two user-visible surfaces** that fix that. They are the live mirror of the tracker; keeping them in sync is non-negotiable.

> **HARD RULE — visibility.** (1) Maintain the native **Task spine** via TaskCreate/TaskUpdate. (2) Emit the **Progress Bar** at every transition boundary (defined below). Both mirror the tracker. Failing to update either after a transition is a protocol violation.

### A. Task spine — native TaskCreate/TaskUpdate (the always-visible panel)

The native task list is what Claude Code renders as a **persistent, always-visible todo panel** (this is exactly how `/prd` gets its beloved todo list — see `framework/.claude/skills/prd/SKILL.md` HARD RULE 4). Keep it **coarse**: one task per card plus a few batch-level framing tasks. Do NOT create a task per phase (that buries the overview).

**When to create (once):** right after Pre-flight has resolved the execution mode (sequential vs team) and, in team mode, the wave layout (`execution_strategy.groups[].level`) — because only then do you know the wave label for each card. Create, in this order:

1. `Pre-flight` — framing task (already in progress by the time you create the spine; mark it `in_progress` immediately and `completed` as soon as the worktree is ready).
2. One task **per card**, in queue order. Subject:
   - **team mode** (wave-labelled): `Wave <level> · <CARD-ID> — <title>` (e.g. `Wave 1 · FEAT-0502 — Add merchant filter`).
   - **sequential mode**: `<CARD-ID> — <title>` (no wave prefix).
3. `Final review` — framing task.
4. `Merge & cleanup` — framing task.

**State transitions (TaskUpdate):**

| Task | → `in_progress` | → `completed` |
|------|-----------------|---------------|
| `Pre-flight` | at spine creation | worktree ready (end of Pre-flight) |
| card task | **Phase 1 step 2b** (claim — when you set the card `status: IN_PROGRESS`) | **Phase 4 step 28** (after commit + `card_status: DONE (verified)`) |
| `Final review` | start of Final Review (F.1) | Final Review complete (fixes applied, build green) |
| `Merge & cleanup` | start of Phase 6 | end of Phase 6c |

**Live sub-state in the subject (optional but encouraged):** while a card task is `in_progress`, you MAY append the current phase to its subject so the panel shows live movement between Progress Bar emissions — e.g. `Wave 1 · FEAT-0502 — Add merchant filter · Phase 3.7 Codex 🔄`. Strip the suffix when the card completes.

In team mode the cards of a wave run in parallel: set ALL of a wave's card tasks `in_progress` when that wave's coders are spawned (Step B), and complete each as its per-card pipeline reaches Phase 4 (team Step D.5/D.6).

### B. Progress Bar — markdown, at transition boundaries

Append this block to your message **at the heavy transition boundaries only** (NOT on every message, and NOT on every intra-card phase change — that accumulates markdown across long autonomous runs; per § "Context economy"). A **heavy transition boundary** is any of: a **card change**, a **wave change**, **any gate decision** (resolved or skipped), and every `AskUserQuestion` / STOP. **Intra-card phase movement** (e.g. Phase 2 → 2.5 → 2.55 within the same card, with no gate decision) is shown via the **Task spine live sub-state** (TaskUpdate, § A above) — NOT by re-emitting this full markdown block each phase.

```
---
📋 **Progresso /new: <batch-id>** — modalità <sequential|team> · Wave <X>/<Y>

| Card | Wave | Fase corrente | Stato |
|------|------|---------------|-------|
| FEAT-0501 | 0 | Phase 4 Commit | ✅ |
| FEAT-0502 | 1 | Phase 3.7 Codex | 🔄 |
| FEAT-0503 | 1 | — | ⬜ |

Gate ledger (card corrente): 2.5b AC-Closure ✅ · 2.55 Simplify ✅ · 2.6 E2E ⏭️ (backend-only) · 3 Doc ⏭️ (light, no-doc-diff→Final) · 3.5 QA ⏭️ (balanced→Final) · 3.7 Codex 🔄
Prossimo passo: <cosa succede dopo>
```

- Legend: `⬜ da fare · 🔄 in corso · ✅ risolto · ⏭️ skippato`.
- The `Wave` column and the `Wave <X>/<Y>` header are present in **team mode** only; in sequential mode drop the column and write `modalità sequential` with no wave counter.
- The **Gate ledger** line shows the current card's per-card gates (see § C for which). Each entry is `<gate> <state>`; a skipped entry MUST carry its reason **verbatim from the enumerated Gate-table / fast-lane skip reasons** — e.g. `IS_TRIVIAL`, `review_profile=light`, `backend-only diff`, `features.has_e2e_review:false`, `balanced→Final`, `holistic_audit provenance`. **Never invent a reason.** A ledger entry reading `⏭️ (time budget)` / `(to save tokens)` / any model-invented constraint is itself a protocol violation (see the top-of-file "NO PHASE SKIP FOR PERCEIVED TIME" clause) — the ledger exists to make skips auditable, not to license them.

### C. Phase → ledger mapping

These are the per-card gates tracked in the Gate ledger line (the rest of the pipeline — Phase 1 context, Phase 2 implement, Phase 4 commit — is shown in the table's "Fase corrente" column, not the ledger):

| Ledger entry | Phase | Skipped when (enumerated reason) |
|--------------|-------|----------------------------------|
| `2.5b AC-Closure` | Phase 2.5b | never (BLOCKING, unconditional) |
| `2.55 Simplify` | Phase 2.55 | `IS_TRIVIAL` |
| `2.6 E2E` | Phase 2.6 | `features.has_e2e_review:false`, backend-only diff, or card type ∈ {backend/api/db/infra/docs/chore/config} |
| `3 Doc` | Phase 3 | `review_profile=light` AND no doc files in diff → deferred to Final F.3 |
| `3.5 QA` | Phase 3.5 | `skip`/`light` (tests already ran Phase 2), or `balanced`→Final (unless Step-A escalation) |
| `3.7 Codex` | Phase 3.7 | `IS_TRIVIAL` only (otherwise unconditional; `light`/`full` is depth, not skip) |

In **team mode** the same gates map to the per-card team sub-steps (D.3a AC-Closure, D.3b Simplify, D.3c E2E, D.4 QA, D.4a/D.2 doc, D.4b Codex) — track them identically. The pre-flight cross-card Codex check (Step 3d) and plan-auditor grounding (Phase 1 step 4) are batch/card-setup gates: surface their resolve/skip in the `Prossimo passo` line or a one-off ledger note, not as recurring per-card rows.

---

## Context economy (MANDATORY)

`/new` runs as a single long-lived orchestrator across a whole batch. Every byte the orchestrator
renders inline (Bash tool-results, agent prompts it composes, files it Reads) stays in its context
window for the **entire** run — there is no real "purge" (the soft "forget" instruction does not
reclaim tokens). On long batches the dominant token cost is **bulk content the orchestrator pipes
through its own inline channel**: gate logs, full `git diff`s, whole-file Reads, concatenated
baselines. Keep that bulk on disk and pass **paths**, not bodies.

> **HARD RULE — bulk content never streams inline.**
> 1. **Gate-output discipline.** Never run a verification gate (`lint` / `tsc` / `test` / `build`)
>    with its output streaming inline — **never `| tee`, never a bare `npm run …`**. Always
>    `cmd > /tmp/<gate>-<CARD-ID>.txt 2>&1` and surface only the exit code inline (`echo "<gate>:$?"`).
>    On failure, surface a **bounded** extract only (`tail -n 30` or `grep -Ei 'error|fail' … | head -n 30`),
>    never the whole log. Pass any fix agent the **file path**, not the inline blob.
> 2. **Diffs to disk.** Capture `git diff` to `/tmp/diff-<CARD-ID>.txt` and pass agents that path —
>    never paste a full diff into a prompt or render it inline. (`git diff --name-only` file *lists*
>    are fine — they are small.)
> 3. **Findings stay file-resident.** Reviewer findings already live in their report files
>    (`/qa/*.md`, `/tmp/codexreview-*.md`). Read a findings file only at the decision point that needs
>    it (merge / domain-route / severity tally) — do not echo finding bodies back into your messages.
> 4. **Pass baseline/report paths, not concatenations.** When briefing a downstream reviewer
>    (e.g. Codex), give it the **list of baseline/report paths** to read on demand rather than
>    inlining their concatenated contents.
> 5. **Targeted Reads.** When verifying code (Phase 2.5), Read only the evidence lines (grep with
>    tight context around the `file:line` the completion report names) — not whole files.
> 6. **Delegate body-heavy setup to a discarded context.** Work whose *output* the orchestrator does
>    not retain — worktree creation + baseline build (invoking `/nw` loads the ~1200-line
>    worktree-manager skill into the cached prefix), external grounding checks — runs in a **background
>    subagent / background Bash**; the orchestrator keeps only the structured verdict (a handful of
>    fields), never the skill body, logs, or trace. And **batch the pre-flight tracker writes into one
>    flush** — pre-flight is idempotent, so per-sub-step Edits are churn the cached prefix re-reads.
>
> This rule is about the **inline channel** and what the orchestrator chooses to retain. It does NOT change any agent's return contract,
> nor what the orchestrator is allowed to read at a decision point — only that bulk arrives via a
> path the consumer opens itself, not via the orchestrator's own context.

---

## Toolchain gates

When `features.has_toolchain: true` in `baldart.config.yml`, every mechanical gate
this skill runs (`lint`, `typecheck`, `test`, `build`) uses the consumer's
configured command from `toolchain.commands.<gate>` **verbatim** instead of the
`npm`/`npx` default shown at the call site — per `framework/agents/toolchain-protocol.md`.
Resolve per gate: a non-empty `toolchain.commands.{lint,typecheck,test,build}` wins;
empty/absent (or the flag off/missing) → the default at the call site, identical to
pre-toolchain behavior. A configured command that exits non-zero is a real gate
**FAIL** — do NOT then run the default (that would mask the failure); fall back only
when the key is **unset**. `npm install` and `markdownlint` are NOT toolchain keys
(there is no `commands.install`, and markdownlint is not in the curated map) — they
stay as written. The gate-output discipline (§ "Context economy" → redirect to disk,
surface only the exit code) applies to the resolved command exactly as to the default.
Reference modules cite this section as `§ "Toolchain gates"`.

---


## Routing — il per-card pipeline e i moduli on-demand

`/new` è uno **orchestrator long-lived**: il suo corpo skill sta nel prefisso di
sistema, ri-letto a OGNI turno. Per non pagare 60k+ token di istruzioni di fase a
ogni turno, il dettaglio passo-passo di ogni fase vive in un **modulo `references/<x>.md`**
caricato on-demand. Questo file (il core) tiene solo gli invarianti cross-fase
(Context Tracking, Progress Visibility, § "Context economy", § "Toolchain gates",
Agent Routing, QA Profile, Trivial fast-lane, Risk-signal detector, Fix Application
Log) + questa mappa di navigazione.

> **HARD RULE — leggi il modulo PRIMA di eseguire la fase.** Quando entri in una
> fase, **Read** il suo modulo `references/<x>.md` e poi eseguilo. Eseguire una
> fase "a memoria" (senza aver caricato il modulo in questo run, o dopo una
> compaction che l'ha evacuato) è una violazione di protocollo: ricaricalo. Registra
> nel tracker, sotto `## Current Card`, il campo `phase_module_loaded: <modulo>` al
> caricamento, così la § "Context recovery protocol" sa cosa ri-leggere dopo una
> compaction. I `§ "..."` citati dai moduli (Context economy, Toolchain gates, Context
> Tracking, Trivial-card fast-lane, Risk-signal detector, Fix Application Log) puntano a
> sezioni che vivono **qui nel core** → risolvono sempre.

**Sequenza (per ogni card, in ordine — i moduli per-card sono caricati per traversata):**

| Fase | Quando | Modulo | Skip se (ragione enumerata) |
|------|--------|--------|------------------------------|
| 0 — Workspace Hygiene + Pre-flight | a inizio batch (una volta) | [`references/setup.md`](references/setup.md) | mai (BLOCKING) |
| 1-2 — Claim & Context + Implement | per card | [`references/implement.md`](references/implement.md) | — |
| 2.5 / 2.5b — Completeness + AC-Closure | dopo l'impl | [`references/completeness.md`](references/completeness.md) | — (2.5b è BLOCKING, mai skip) |
| 2.55 / 2.6 / 3 / 3.5 — Simplify + E2E + Doc + QA | dopo AC-Closure | [`references/review-cycle.md`](references/review-cycle.md) | `IS_TRIVIAL`→skip 2.55+3.5; `has_e2e_review:false`/backend-only→skip 2.6; `light`+no-doc-diff→Doc a Final; `balanced`→QA a Final. **Il cluster discovery+fix 2.55+3.5+3.7 delega al workflow `new-card-review` se il tool `Workflow` è disponibile (review-cycle.md § Phase 2.5x — poi E2E→Doc→Commit); altrimenti inline. E2E (2.6) e Doc (3) restano sempre nella skill.** |
| 3.7 — Pre-Merge Codex Review Gate | pre-commit | [`references/codex-gate.md`](references/codex-gate.md) | solo `IS_TRIVIAL` (altrimenti unconditional; `light`/`full` è DEPTH, non skip). **Coperta dal workflow `new-card-review` quando il cluster è delegato (codex-gate.md carve-out).** |
| 4-5 — Commit + Context Clean | fine card | [`references/commit.md`](references/commit.md) | — |
| Final review F.1-F.6 | dopo l'ultima card | [`references/final-review.md`](references/final-review.md) | mai (FULL gate unconditional). **F.2–F.4 delegate al workflow `new-final-review` se il tool `Workflow` è disponibile (Step F.1.5); altrimenti inline.** F.5/F.6 sempre nella skill. |
| 6 / 6b / 6c — Merge & cleanup | dopo Final | [`references/merge-cleanup.md`](references/merge-cleanup.md) | mai (BLOCKING) |
| 7 — Production Readiness | dopo il merge | [`references/production-readiness.md`](references/production-readiness.md) | — |
| 8 — Metrics Log | ultimo | [`references/metrics.md`](references/metrics.md) | mai (non-blocking, best-effort) |

**Team Mode** (batch complessi, deciso in Pre-flight per § "Parallelism rules"): il
per-card pipeline sopra è rimpiazzato dall'esecuzione per-gruppo parallela —
[`references/team-mode.md`](references/team-mode.md). Le stesse fasi/gate sono propagate
per-card nei sub-step D.x (mai aggregate). Caricalo quando Pre-flight seleziona team mode.

---

## Parallelism rules

### Sequential mode (default for small batches)

- Cards execute one at a time through the full per-card pipeline (Phases 1-5).
- Code review and doc review for the same card run as **parallel read-only audits**, then fixes are applied by domain owner (see § "Domain-Override Domains"): **doc findings → `doc-reviewer` (write mode)**, **security findings → `security-reviewer` (write mode)**, code/perf/migration findings → `coder`. (Sequential Phase 3 is even simpler — doc-reviewer runs alone, so it audits AND applies in one invocation.)
- This mode is unchanged from the original behavior.

### Team mode (for complex batches)

- Cards within the same `execution_strategy.groups` level (same `level`) run in parallel via isolated coder agents.
- Groups execute sequentially (group 0 → group 1 → group 2...).
- Review + QA run ONCE per group (combined), not per card.
- The orchestrator holds ONLY coordination state, never implementation details.
- File ownership map is enforced per-agent via MAY EDIT / FORBIDDEN lists.
- See "Team Mode" section below for full workflow.

### Common rules (both modes)

- The file-ownership map is the authoritative source for which files each agent may edit.
- When running parallel agents, expect "file modified since read" errors on shared files (like the backlog yml) — handle gracefully.
- When running in parallel, each parallel branch updates the tracker with its own card — use card ID as prefix to avoid conflicts.

---


## Context recovery protocol

If at ANY point you are unsure where you are in the batch:
1. Read your tracker file (`/tmp/batch-tracker-<FIRST-CARD-ID>.md`)
2. Check `## Current Card` — if populated, resume that card at the listed phase.
2b. **Pre-flight not finished?** If `## Current Card` is empty / `(none — starting pre-flight)` AND `## Worktree` still shows skeleton placeholders (no real `Path:`/`Port:`), then a compaction hit mid-pre-flight (most likely during the step-5 background barrier). Re-enter **Pre-flight at step 4** (Read the `setup.md` module first per § "Routing"): its step-4a2 git pre-check re-detects an already-created worktree via `git worktree list` and resumes-or-resets it safely — so re-entry never double-creates or fails-loud.
3. **Re-Read the phase module** named in `## Current Card`'s `phase_module_loaded:` field (a compaction may have evacuated it from context — see § "Routing" HARD RULE). If the field is absent, map the listed phase to its module via the § "Routing" table and Read that.
4. Check `## Card Queue` — find the next unchecked card.
5. Check `## Completed Cards` — know what's already done (don't redo).
6. Continue the pipeline from where you left off.

---


## Agent Routing (Phase 2 dispatcher)

Phase 2 reads the card's `owner_agent` field and dispatches to the matching
specialist. The enum's single source of truth is the **`owner_agent enum` block in
`framework/.claude/agents/REGISTRY.md`** (applied by `prd-card-writer.md § Agent
Specialization Rules`) and validated by the PRD validation phase
(`framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0).

| `owner_agent` | Dispatcher action in Phase 2 step 7 | Briefing variant |
|---|---|---|
| `coder` | Spawn `coder` | Standard coder briefing (default body below) |
| `ui-expert` | Spawn `ui-expert` | UI briefing — adds BLOCKING registry-first cascade + Post-Intervention Coherence Check (see step 7 § UI branch) |
| `plan` | Fallback to `coder` + WARN | Standard coder briefing + log `"[ROUTER] plan-only briefing not yet implemented — using coder"` |
| `visual-designer` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
| `motion-expert` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
| missing / `""` / `claude` (legacy placeholders only) | Fallback to `coder` + WARN | Standard coder briefing + log `"[ROUTER] card <ID> has no valid owner_agent (got '<raw>'); defaulting to coder"` |
| any other unrecognized value (typo, unregistered agent) | **HALT + ask the user** | No briefing — the router stops and surfaces the literal value (see pseudocode step 6b) |

The three `plan` / `visual-designer` / `motion-expert` stubs exist so the
router never blocks a card; specialized briefings are tracked as a follow-up.
**Only the empty/missing/`claude` legacy placeholders fall back to `coder`** — a
genuinely unrecognized value (e.g. a typo `coder-agent`, or an agent not in the
enum) HALTs so a mis-routed card is never silently downgraded. The table and the
step-6b pseudocode are the same contract stated twice; keep them in lockstep.

The valid values come from ONE place — `REGISTRY.md`'s `owner_agent enum` block. Do not
re-list them here or maintain parallel copies; if the roster changes, edit the enum in
`REGISTRY.md` and these consumers read it:

- `framework/.claude/skills/prd/assets/card-template.yml` (the placeholder cites the REGISTRY enum),
- `framework/.claude/agents/prd-card-writer.md § Agent Specialization Rules`,
- `framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0a,
- `framework/.claude/agents/REGISTRY.md` decision-tree.

Keep them in lockstep — drift between any two layers silently mis-routes cards.

---


## QA Profile Selector

Before Phase 3.5, determine the review profile for each card. **`/new` is a CONSUMER of `review_profile`, not the place where the decision criteria live.**

**Primary path (deterministic — since v3.38.0): READ `review_profile` from the card YAML.**
The PRD `prd-card-writer` computes this field at authoring time — the decision criteria
(how `skip`/`light`/`balanced`/`deep` is chosen, including the `>15-file → deep` trigger and
the `feature`/`enhancement` ≥ balanced floor) are the **SSOT in `prd-card-writer.md § Rule C`**.
They are deliberately NOT reproduced here. If the card has a `review_profile` ∈ {`skip`,
`light`, `balanced`, `deep`}, **use it verbatim** — do NOT recompute. Log `profile=<x> (from card)`
in the tracker.

**By this point `review_profile` is always present.** Pre-flight step 1b-ii (`setup.md`) already
**normalized** every ingested card — a legacy/manual/foreign card that lacked the field had it
back-filled via `prd-card-writer.md § Rule C` and **persisted to disk** (with a `[BACKFILL]` log),
so this selector is a pure read. The compute-from-Rule-C logic lives ONLY at 1b-ii — there is no
second copy of the criteria here, which avoids the drift that previously let the two tables
disagree. Defensive one-liner only: if a card somehow still lacks the field (validator skipped in
this install), compute it via Rule C and log `profile=<x> (computed — review_profile absent)` —
but the canonical write happened at 1b-ii.

> Note: the qa-sentinel agent keeps its OWN, different mapping (`profile → SCOPED/FULL` test tier),
> which is legitimately qa-sentinel's; that is not the same thing as this profile-selection criteria.

---


## Trivial-card fast-lane (since v4.6.0 — SSOT; phases below CITE this, never redefine it)

Some cards are genuinely too small to justify the review machine: a `docs`/`chore`/`config`
card, a copy fix in a `.md`, a one-line `ssot-registry` update, a non-API `.yml` bump. Running
codebase-architect + plan-auditor + code-reviewer + Codex + the QA test suite on a diff that
contains **no source code** is pure waste — there is nothing for those agents to review. The
fast-lane routes such cards through the minimal safe tail. It is a **per-card** property
(applies in BOTH sequential and team mode), and it is the polar opposite of a `time budget`
skip: it is gated entirely on deterministic, PRD-authored signals.

### The classifier — `IS_TRIVIAL(card)` (ALL three must hold — AND)

1. **`review_profile == skip`** — read verbatim from the card YAML. Per `prd-card-writer.md § Rule C`,
   `skip` is assigned to `docs`/`chore`/`config` cards, all-non-logic-file cards, and pure-cosmetic
   cards (typo/rename/copy/wording/style). This is NOT the epic guard (an epic is never implemented;
   a trivial card IS implemented, just with a minimal tail). **AND**
2. **Zero Step-A high-risk triggers** — run the Phase 3.7 **Step A** detector (the same bash+grep:
   high-risk module from `paths.high_risk_modules` / dead-code resurrection / reference-aliasing) on
   this card's diff. Any trigger ⇒ NOT trivial. **AND**
3. **Non-source diff** — `git diff --name-only` (working-tree pre-commit in sequential; `$TRUNK...HEAD`
   post-commit in team mode) contains **NO file matching the source-extension predicate**
   (reuse/extend the Phase 2.6 backend-only predicate):
   ```bash
   SRC_RE='\.(tsx?|jsx?|mjs|cjs|vue|svelte|css|scss|py|go|rs|java|rb|php|sql|prisma)$'
   if echo "$CHANGED" | grep -qE "$SRC_RE"; then IS_TRIVIAL=0; else IS_TRIVIAL=1; fi
   ```
   Only `.md` / `.json` / `.yml` / `.yaml` / `.txt` / `.csv` and doc paths qualify.

**Fail-safe guard (degrade toward MORE review, never less)**: if ANY condition fails — a single
source file in the diff, one Step-A trigger, or a non-`skip` profile — `IS_TRIVIAL=false` and the
card follows its normal path (in team mode that is `LIGHT_CARDS`: D.4b `/codexreview` at `light` —
Codex finder + FP-gate — plus the Final FULL gate; in sequential, the full per-card pipeline). A mis-authored `skip` on a code card, or a `skip` card
whose text mentions `auth`/`payment`/etc., is therefore always caught. The classifier can only ever
*remove* review from a card that demonstrably has no code to review.

### What a trivial card runs vs skips

| Step | Trivial card |
|------|--------------|
| codebase-architect grounding (Phase 1 step 3) | **SKIP** (non-source, self-contained) |
| plan-auditor grounding (Phase 1 step 4) | **SKIP** (depends on architect findings) |
| coder (Phase 2) | **RUN** — briefing degrades to card-spec + target file from `files_likely_touched` (no architect section) |
| mechanical gates | **RUN INLINE** — `markdownlint` on changed `.md`, `lint` on lintable files, `build` as a sanity check (NO qa-sentinel spawn, NO test suite) |
| Phase 2.5b / D.3a AC-Closure | **RUN** (scope discipline, inline, cheap — never skipped) |
| Phase 2.55 / D.3b Simplify | **SKIP** |
| Phase 2.6 / D.3c E2E | **SKIP** (already gated by `docs`/`chore`/`config` type) |
| Phase 3 / D.4a doc-review | **RUN** (the relevant reviewer for docs/ssot) |
| Phase 3.5 / D.4 QA test suite | **SKIP** (covered by inline mechanical gates above) |
| Phase 3.7 / D.4b Codex | **SKIP** |
| commit + backlog | **RUN** |
| **Final Review F.3** | **RUNS (unconditional net)** — covers every trivial card in the batch-wide gate before merge |

Every skip above is logged with the enumerated reason `trivial: review_profile=skip + non-source
diff + 0 triggers` — a deterministic, card-authored gate reason. Never `time budget`.

---


## Risk-signal detector (Phase 3.7 Step A — signal-logging only, NEVER gates the next step)

> Questo detector vive nel core perché due consumatori lo usano in momenti diversi:
> la § "Trivial-card fast-lane" (a Phase 1, per classificare la card) e il modulo
> `references/codex-gate.md` (a Phase 3.7, Step B/C). È deterministico (grep + path
> match), non LLM-discrezionale, e **non gate mai** il passo successivo.


Run this exact bash block in the worktree. It is deterministic (grep + path match), not LLM-discretionary.

`$TRUNK` is the trunk branch resolved in Phase 0 (`git.trunk_branch`, autodetected when the key is absent — see Phase 0 step 0). `$HIGH_RISK_RE` is an alternation built from `paths.high_risk_modules` in `baldart.config.yml` (e.g. `path1|path2|withAuth`). **If `paths.high_risk_modules` is absent, the path-based triggers (#1) emit a one-line diagnostic and match nothing — no hardcoded project path is baked in.** `BACKLOG_DIR` is the value of `paths.backlog_dir` from `baldart.config.yml` (fallback `backlog` when the key is absent — emit it resolved, never the literal `${paths.backlog_dir}` token, which is not valid bash). The card lookup uses `-iname` (case-insensitive) on purpose: card filenames carry uppercase prefixes (`FEAT-`/`BUG-`/`CHORE-`) but `CARD_ID` may arrive lowercased (e.g. `/new feat-0019`), and a case-sensitive `-name` would return empty silently → the card would be treated as non-existent.

```bash
cd <worktree-path>
CARD_ID="<CARD-ID>"
BACKLOG_DIR="<value of paths.backlog_dir, or 'backlog' if the key is absent>"
CARD_FILE="$(find "$BACKLOG_DIR" -iname "${CARD_ID}*.yml" 2>/dev/null | head -1)"
# Detect what THIS card's commits changed against the trunk (post-commit), with an uncommitted fallback:
CHANGED="$(git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD)"
# High-risk path alternation from config (empty when paths.high_risk_modules is unset):
HIGH_RISK_RE="<alternation of paths.high_risk_modules entries, or empty>"

TRIGGERS=()

# Trigger #1 — High-risk module (auth / permission / payment / shared scoring-or-ranking primitive)
# Sourced from paths.high_risk_modules — NOT a hardcoded project path.
if [ -n "$HIGH_RISK_RE" ]; then
  echo "$CHANGED" | grep -qE "$HIGH_RISK_RE" \
    && TRIGGERS+=("#1: high-risk module (paths.high_risk_modules)")
else
  echo "[DETECTOR] paths.high_risk_modules absent — path-based high-risk trigger skipped" >&2
fi

# Trigger #2 — Dead-code resurrection (card text + commit messages)
{ cat "$CARD_FILE" 2>/dev/null; git log --format=%B "$TRUNK...HEAD" 2>/dev/null; } \
  | grep -qiE 'dead code|unreachable|resurrect' \
  && TRIGGERS+=("#2: Dead-code resurrection")

# Trigger #3 — Reference-aliasing mutation pattern (in-place array reset + push)
# Card introduces or modifies an exported helper AND a call site in the diff mutates an input
# array in place via `length = 0` + `push(...result)`. Even with a local identity guard, the
# high-risk gate runs adversarial review to confirm the contract is robust against future callers.
# Iterate file-by-file safely (no unquoted xargs filename expansion):
RESET=""; PUSH=""
while IFS= read -r f; do
  [ -n "$f" ] || continue
  C="$(git show "HEAD:$f" 2>/dev/null)" || continue
  printf '%s' "$C" | grep -qE '\.length\s*=\s*0' && RESET=1
  printf '%s' "$C" | grep -qE '\.push\(\s*\.\.\.' && PUSH=1
done <<< "$CHANGED"
[ -n "$RESET" ] && [ -n "$PUSH" ] \
  && TRIGGERS+=("#3: Reference-aliasing mutation pattern")

printf '%s\n' "${TRIGGERS[@]}"
```


---

### Fix Application Log Schema (telemetry)

Every fix-application decision in Phases 2.55 / 3 / 3.5 / 3.7 appends one row to the tracker's `## Fix Application Log` section. Telemetry only — does NOT alter behaviour. The aggregated log feeds `framework/scripts/analyze-fix-application.js`, which surfaces which fixes the orchestrator applied inline vs delegated to coder, per-phase distribution of `est_lines`, and violation patterns (doc/security findings applied inline). Full reading guide: `framework/docs/FIX-APPLICATION-TELEMETRY.md`.

**Row format** (one row per finding processed, including skipped):

```
<phase> | <domain> | est_lines=<n> | decision=<inline|coder|coder-batch|doc-reviewer|skipped> | applied_by=<orchestrator|coder|doc-reviewer|orchestrator-fallback|-> | <key=val>...
```

| Field | Values |
|---|---|
| `phase` | `2.55`, `3`, `3.5`, `3.7`, `D.4a` (team-mode doc gate) |
| `domain` | `simplify-reuse`, `simplify-quality`, `simplify-efficiency`, `doc`, `qa-blocker`, `qa-major`, `qa-minor`, `qa-none`, `codex-security`, `codex-correctness`, `codex-other` |
| `est_lines` | Orchestrator's at-a-glance estimate of the diff size suggested by the finding. Bucketed `1-5` / `6-20` / `21+` is sufficient — exact precision not required. Use `0` if no patch (e.g. skipped). |
| `decision` | `inline` (orchestrator applied), `coder` (single coder spawn for this finding), `coder-batch` (folded into a batched coder spawn covering ≥2 findings), `doc-reviewer` (doc-domain fix applied by the doc-reviewer in write mode — since v3.40.0), `skipped` (false positive / not worth addressing / no findings) |
| `applied_by` | `orchestrator`, `coder`, `doc-reviewer` (doc-domain owner — since v3.40.0), `orchestrator-fallback` (agent crash with non-domain-override fallback — see Sub-agent failure protocol), `-` (skipped) |
| Trailing `key=val` | Phase-specific extras: `finding=<1-line summary>`, `severity=<BLOCKER\|HIGH\|MEDIUM\|FALSE-POSITIVE>`, `retry=<n>`, `reason=<...>` |

**Write target**: the same tracker file the orchestrator already writes per-card status to (path resolved from `${paths.references_dir}/trackers/` or the project's tracker convention). Section header `## Fix Application Log` is created on first row of the card. Append-only — never rewrite previous rows.

**Cost**: ~80-120 bytes per row, ~5-15 rows per card. Negligible context impact, large analytical value.

#### Domain-Override Domains (since v3.28.3)

Some fix domains are **never** safe for inline orchestrator apply, regardless of size — the orchestrator MUST delegate every fix in these domains to the **domain-owning agent**, even when the patch is a one-liner. The owning agent is the one whose system prompt + project overlay encodes that domain's invariants; an orchestrator inline edit (or a fix routed to the wrong agent) routinely breaks them.

Enumerated exhaustively:

| Domain | Owning agent | Match rule |
|---|---|---|
| `doc` | **`doc-reviewer`** (write mode) | File path matching `*.md` under `${paths.references_dir}`, `${paths.prd_dir}`, project root `CHANGELOG.md`, or any `ssot-registry.md`. |
| `security` | **`security-reviewer`** (write mode) | File path matching any entry in `paths.high_risk_modules` (`baldart.config.yml`) — the same auth/permission/payment-class paths the Phase 3.7 Step A detector reads. Also any SQL migration whose content matches `CREATE POLICY|ALTER POLICY|DROP POLICY` (RLS policy mutations). If `paths.high_risk_modules` is absent, the security match rule emits a one-line diagnostic and matches nothing (no hardcoded default). |
| `migration` | `coder` | File path matching `${paths.migrations_dir}/*.sql` if `paths.migrations_dir` is defined in `baldart.config.yml`; otherwise the project's migrations dir per convention (`migrations/`, `db/migrate/`, `supabase/migrations/`, `prisma/migrations/`). |

**Why `doc` is owned by `doc-reviewer`, not `coder` (since v3.40.0)** — the doc invariants the orchestrator must not break (freshness markers, linking protocol, frontmatter standard, tabular formatting, SSOT/registry coverage, dependency-topological order, SCIP/code refs) are encoded in the **`doc-reviewer`** system prompt, NOT the coder's. The coder is a code-oriented agent that lacks the doc-invariant contract — routing doc fixes to it is the wrong agent doing work the auditing agent already has full context for. The agent that *audits* the docs is also the agent that *fixes* them (`doc-reviewer.md` § Constraints: "WRITE missing docs directly. You are fully responsible — do not defer to other agents"). NEVER route a `doc`-domain fix to `coder`.

**Why `security` is owned by `security-reviewer`, not `coder` (since v4.36.0)** — the same logic as `doc`, applied to the security domain (canonical writer map v4.26.1; user principle "il codice lo scrive solo coder, la security solo security-reviewer"). The auth/permission/RLS/multi-tenant-isolation invariants live in the **`security-reviewer`** system prompt, not the coder's; a coder applying a one-line RLS or permission fix without that contract is the same class of error as the "wrong agent for the card". `security-reviewer` is the writer for security-domain fixes — it audits AND applies. `migration` stays `coder` (SQL authoring is the coder's lane; a migration's security-policy content matching the RLS rule above is classified `security`, not `migration`). NEVER route a `security`-domain fix to `coder`.

**Edge case explicit** — a mechanical append-a-row update to `CHANGELOG.md` or `ssot-registry.md` is still classified `doc` and still goes through `doc-reviewer`, never inline and never `coder`. The uniformity of the rule matters more than the cost of the individual spawn.

Domains NOT listed here remain governed by the per-phase rules of the corresponding phase (e.g. `simplify-*` follows Phase 2.55 inline rule).
