---
name: new2
effort: high
description: >
  EXPERIMENTAL workflow-hosted variant of /new (A/B testing). Implements one or
  more backlog cards end-to-end by delegating the WHOLE batch to a background
  dynamic workflow — so subagent output never enters the main orchestrator
  context. Fully autonomous (zero AskUserQuestion): every /new gate is replaced by
  a deterministic policy + a self-healing resolution pass. Claude-only (needs the
  Workflow tool). Usage: /new2 CARD-IDS (same arg grammar as /new). Triggers on:
  /new2, "implementa le card con workflow", "new2".
---

> **EXPERIMENT — not a replacement for `/new`.** `new2` exists to A/B-test the
> context-economy of hosting the batch orchestration inside a Claude Code dynamic
> workflow instead of the main loop. `/new` remains the SSOT, the cross-tool
> default, and the recovery-safe path. Do NOT route to `new2` unless the user
> explicitly asks for it.

> **ZERO-ASK CONTRACT.** A dynamic workflow cannot prompt the user mid-run. `new2`
> therefore runs the entire batch autonomously: every `/new` `AskUserQuestion`
> gate is replaced by a deterministic policy (auto-resolve seamless defaults, or
> fail → self-healing `new2-resolve`, or — last resort — auto-materialise a
> tracked follow-up card). Destructive/outward ops (`reset --hard`, force-push,
> stash drop) are NEVER auto-run; they degrade to "leave intact + report".

## Project Context

**Reads from `baldart.config.yml`:** `paths.backlog_dir`, `paths.references_dir`, `paths.metrics`, `paths.high_risk_modules`, `git.trunk_branch` (autodetected from `origin/HEAD` when absent), `git.merge_strategy`, `stack.*` (incl. `stack.schema_deploy_from_trunk_only` — the trunk-only schema-deploy gate guard), and `features.has_e2e_review` / `features.has_design_system` / `features.has_lsp_layer`.
**Gated by features:** `features.has_backlog` (REFUSES to run when `false` — operates on backlog cards by definition).
**Overlay:** loads `.baldart/overlays/new.md` if present (shared with `/new`: canonical-docs registry, tooling paths).
**On missing/empty keys:** the deterministic pre-flight autodetects (trunk via `origin/HEAD`); only HALT when nothing resolves. See `framework/agents/project-context.md` § 3.

## Effort

**Baseline:** `effort: high` (frontmatter — the workflow runs a full implement+review
batch autonomously, so it warrants deep reasoning). **Inline override:** pass
`effort=<low|medium|high|xhigh|max>` anywhere in the invocation; detect once at
kickoff, strip the token, and forward it to the workflow via `args.flags.effort`
(agents inside the workflow honour it). Mapping/parsing: `framework/agents/effort-protocol.md`.

---

## What this skill does (thin coordinator — keep it out of the way)

`new2` holds **almost no content in the main loop**. Its entire job is: parse the
invocation, gather project facts, hand the batch to the `new2` background workflow,
and present the report it returns. All the heavy orchestration (architect, coder,
reviewers, Codex, QA, E2E, merge) lives in the workflow's isolated runtime — its
output never lands in your context.

### Step 1 — Degradation gate (BLOCKING, first thing)

`new2` is **useless without the `Workflow` tool** (its whole point is the background
runtime). If the `Workflow` tool is **not available** in this session (OpenAI Codex
install — workflows are Claude-only; `disableWorkflows` set; or a Claude Code older
than the dynamic-workflows research preview), do NOT attempt any fallback:

> Print: `"/new2 richiede i dynamic workflow di Claude Code (non disponibili in questa sessione). Usa /new — stessa semantica, esecuzione nel main loop."` and **HALT**.

Also verify the workflow script is linked: if `.claude/workflows/new2.js` is absent,
print the same guidance and HALT (the framework did not link it — Codex tree, or a
pre-v4.16 install).

### Step 2 — Parse the invocation (same grammar as `/new`)

Parse `CARD-IDS` exactly as `/new` does — space-separated, hyphen-range
(`GLOB-001-GLOB-008`), comma-separated, and **epic expansion** (`-full` / `--full`
expands all children of a parent: filename prefix `<PARENT>-` ∪ cards whose
`group.parent == <PARENT>`, parent excluded, sorted by `group.sequence`). Strip the
`-full` / `--full` and `-stats` / `--stats` tokens and the `effort=<level>` token
before treating the rest as card IDs. If no card IDs are given, ask which cards
(this is the ONE pre-launch question — it is NOT a mid-run gate). Resolve each card
to its backlog YAML path under `${paths.backlog_dir}`.

### Step 3 — Feature gate + gather facts

- Read `features.has_backlog`. If `false` → print the same refusal as `/new`
  (`"requires features.has_backlog: true — run npx baldart configure"`) and HALT.
- Read `baldart.config.yml` and resolve: `$MAIN` (the main repo absolute path — walk
  up from a worktree if needed), `$TRUNK` (`git.trunk_branch`, else autodetect via
  `git symbolic-ref refs/remotes/origin/HEAD` → `develop`/`main`/`master`), `$METRICS`
  (`paths.metrics`, default `docs/metrics`), and the `paths.*` / `stack.*` /
  `features.*` the agents will need. Resolve `refModulesBase` = the directory holding
  `/new`'s reference modules (`.claude/skills/new/references` — the workflow's agents
  Read them for the review SEMANTICS, so `new2` stays a thin orchestration host and
  the A/B test isolates the host, not the protocol).

### Step 3.5 — Migration Gate (BLOCKING only when a migration is *declared* — else a silent no-op)

The workflow runs autonomously and **cannot** apply an owner-gated DB migration mid-run, so today a
declared migration is deferred to the end of the batch — and every downstream card is built and
verified against a schema that is not yet live (`validation_commands` / QA / E2E / DB-generated `tsc`
types fail falsely → those cards cascade into deferral). This gate front-loads the migration: it runs
**here, in the skill** (the main loop — it can interact; the workflow's zero-ask contract is
untouched), so the schema is live **before** the workflow starts. It mirrors `/new` Phase 0 step 1b
(`references/setup.md`) — same algorithm, same `migration_plan` epic-card convention.

1. **Find the batch's epic card(s)** — distinct `group.parent` of the resolved cards (or the `-full`
   parent). Read each epic YAML in `${paths.backlog_dir}` (`<PARENT>-*-epic.yml`, or the card whose
   `id == <PARENT>` / `group.is_epic: true`).
2. **Look for `migration_plan` with `required: true`.** None → set `migration = { status: 'none' }`
   and go to Step 4 (identical to today — zero extra prompts; do not surface anything).
3. **(declared) Verify `migration_plan.artifacts` exist on disk under `$MAIN`.** Any missing → do NOT
   apply or prompt; set `migration = { status: 'degraded', reason: 'artifact missing', artifacts }`
   and go to Step 4 (the migration falls back to the current end-of-batch owner-gated deferral — no
   regression).
4. **(declared + present) Assemble the apply modalities**, de-duped by `id`, in source order:
   (a) `migration_plan.apply_modalities`; (b) a `## Migration modalities` section in
   `.baldart/overlays/new.md`; (c) any project-memory note on how this project applies migrations;
   (d) built-in tail `["Già applicata — prosegui", "Abort"]`.
5. **`AskUserQuestion`** — `"La epic dichiara una migrazione DB (<summary>). La applico PRIMA del
   batch così le card downstream verificano contro lo schema reale. Come procedo?"` with up to 4
   modalities (always include "Già applicata — prosegui" and "Abort"). This is the SAME class as the
   Step-2 "ONE pre-launch question" — pre-launch, not a mid-run gate; the zero-ask contract is about
   the *workflow*, which is untouched.
6. **Execute the choice in `$MAIN`**:
   - **Schema-deploy-from-trunk-only guard** (when `stack.schema_deploy_from_trunk_only: true`): a
     **command** modality is a remote schema deploy → run it only from trunk. Check
     `git -C "$MAIN" rev-parse --abbrev-ref HEAD`; if it is not `git.trunk_branch`, do NOT apply a
     command modality — set `migration = { status: 'degraded', reason: 'off-trunk: schema_deploy_from_trunk_only' }`
     and skip to Step 4 (the migration falls back to the workflow's end-of-batch owner-gated deferral →
     a `db-migration-deploy` residual; apply it from trunk, then re-run). "Già applicata — prosegui"
     stays valid (no deploy). No-op when the key is `false`/unset.
   - a **command** modality → run with output to `/tmp/migration-<firstCard>.log`, surface only the
     exit code; on exit 0 run the optional `migration_plan.verify` probe and require it green. On
     failure → bounded extract (`tail -n 30`) + re-ask. **Never run a command the user did not pick.**
   - **"Già applicata — prosegui"** → run `verify` if present; else trust the user.
   - **"Abort"** → HALT cleanly; do NOT call the workflow.
7. **Build the manifest** to pass to the workflow:
   `migration = { status: 'applied'|'skipped', modality: <id>, summary, artifacts: [...], affects_cards: [...], appliedAt: ts }`.

### Step 4 — Delegate the whole batch to the workflow

Call the `Workflow` tool:

```
Workflow({ name: 'new2', args: {
  cardIds,            // expanded list (ranges/-full already resolved here)
  cardPaths,          // resolved backlog YAML paths
  mainRepo,           // $MAIN absolute path
  trunk,              // resolved $TRUNK
  metricsDir,         // $METRICS
  refModulesBase,     // .claude/skills/new/references (semantic SSOT)
  config,             // the parsed baldart.config.yml (paths.*/stack.*/features.*/git.*)
  ts,                 // ISO timestamp NOW — the workflow has no clock (Date.now() unavailable there)
  migration,          // Step-3.5 manifest: { status:'none'|'applied'|'skipped'|'degraded', modality?, summary?, artifacts?, affects_cards? }
  flags: { stats, effort, full }
}})
```

Record the kickoff time (`ts`) before the call — Step 5 uses it to stamp the
real wall-clock duration (the workflow cannot read a clock).

The workflow runs the entire batch in the background. **Do not poll it** — it
returns when the batch is done. It returns:

```
{ report, perCardResults, gateLedger, residualFollowups, residuals,
  degraded, degradationReasons, telemetry }
```

- `report` — ready-to-show markdown batch summary.
- `residuals` — the **OFFLINE-SAFE ledger of record**: every residual the workflow
  could not finish, each `{ card, kind, evidence, materialized }`. The `materialized`
  flag is **advisory only** — `true` means the workflow *attempted* a write (possibly
  into a worktree that never merged), not that a card exists on disk in the main repo.
  **You (the skill) must reconcile EVERY residual against the main-repo disk** (Step 5.1).
  **v4.31.0 — the workflow now self-corrects this ledger before returning**: it re-verifies
  every still-pending code/doc residual against the worktree HEAD and **retracts the ones a
  later in-batch commit already satisfied** (telemetry `ledger_reconciled`), and **collapses
  duplicate owner-gated residuals that map to one external action** (e.g. one migration's
  `db:push` re-raised per-card + batch-wide → telemetry `owner_gated_deduped`). So `residuals[]`
  arrives pre-cleaned of false-open and duplicate entries; your Step 5.1 disk reconciliation is
  now a **safety net** over a clean ledger (it still runs — the self-correction is conservative
  and F-040 worktree-not-merged still applies), not the sole defence.
- `degraded` / `degradationReasons` — the batch stopped early under a sustained
  outage (or another degradation). The batch is NOT complete; it must be resumed.
- `telemetry` — the Phase-8 record (`variant:"new2"`).

### Step 5 — Reconcile, resume, present, record

1. **Materialise follow-ups in the MAIN repo — verify on disk, do NOT trust `materialized`
   (F-040).** The workflow's agents run cd'd into the *worktree*, so any follow-up they wrote
   may live in a worktree that was NOT merged (and is now gone) — `materialized:true` only means
   "the workflow attempted a write", never proof on disk. So for **every** `residuals[]` entry
   (regardless of the `materialized` flag), check whether a matching follow-up card actually exists
   on disk under `${paths.backlog_dir}` in the **MAIN repo** (`<card>-followup-*.yml`). If it is
   absent, create it by **delegating to the `prd-card-writer` agent in Standalone Single-Card Mode**
   — the same owner the workflow uses (full STANDALONE baseline of `framework/agents/card-schema.md`:
   Rule C `review_profile`, `owner_agent` routed to the residual's domain, `scope`, traceability) —
   derived from the residual (≥1 requirement; `acceptance_criteria` = the verbatim residual;
   `files_likely_touched` from the card's ownership). Do NOT hand-write a minimal stub — the offline
   path must match agent-path quality (F-039); it MUST pass the `/new` pre-flight field check. If
   `prd-card-writer` is unavailable (total outage), fall back to a minimal valid stub carrying the
   step-1b HALT fields — the `/new` pre-flight back-fill (step 1b-ii) then normalizes its
   `review_profile`/`owner_agent` on first ingestion, so even the crisis stub self-heals. This
   main-repo, **disk-verified** write is the SSOT — nothing is dropped even on a non-merged batch.
2. **Mark deferred cards DONE — only after their follow-up exists AND every deferral class allows
   it (F-040/H + A3).** Some committed cards were intentionally left **NON-DONE** because they carry
   an open deferred AC: they are `perCardResults[]` entries with `deferred:true` plus a
   `deferredClasses[]` array (also `cards_deferred_done_pending` in telemetry + the `F040-deferred`
   ledger row). For each such card, **check the classes first**:
   - **Every class ∈ {`owner-gated`, `not-a-code-defect`, `policy-deferred-ac`}** → the card's own
     code is complete; the residual is an external/infra step. Now that step 1 guaranteed its
     deferral's follow-up exists on disk in the main repo, set the card `status: DONE` +
     `completed_date` + an implementation_note (`"DONE post-run (new2) — AC deferred to follow-up
     <id>"`) in `${paths.backlog_dir}/<card>.yml`, and fold all of them into ONE reconciliation
     commit in the MAIN repo.
   - **ANY class ∈ {`unresolved`, `out-of-ownership`, `outage`} (or missing)** → the card's DoD is
     genuinely NOT met (an AC the workflow tried and failed to implement). Leave it **IN_PROGRESS**
     and surface it explicitly in the presentation: `"commit landed, DoD NON soddisfatta —
     follow-up <id>"`. NEVER auto-DONE it — a follow-up tracks the gap, but DONE would lie (F-029).
   **If a card's follow-up could NOT be created in step 1, leave it NON-DONE and surface it** —
   fail-loud; NEVER mark a card DONE with a silently-dropped requirement (F-029).
   **Then re-run the epic-closure check for the cards just marked DONE.** The merge agent's
   epic-closure (Phase 6b step 5e) ran BEFORE this step, when the deferred cards were still
   NON-DONE — so an epic whose last open child was a deferred card is still TODO and nothing
   else will ever close it. For each distinct `group.parent` of the cards marked DONE here: if
   `grep -l "parent: <EPIC-ID>" ${paths.backlog_dir}/*.yml | xargs grep -L "status: DONE"`
   prints nothing, set the epic card `status: DONE` + `completed_date` + note
   `"epic-closure gate — all children DONE (post-run, new2 skill)"`, folded into the SAME
   reconciliation commit. If any child is still open, leave the epic untouched.
3. **Resume if degraded.** If `degraded` is true, re-invoke the workflow with
   `Workflow({ scriptPath, resumeFromRunId })` (same `args` + the new `ts`). The
   per-card **skip-completed** guard makes the resume idempotent — already-committed
   cards are skipped, only the incomplete/blocked ones run. Repeat until `degraded`
   is false (or the same cards stall twice → surface to the user).
4. **Present.** Print `report` verbatim. Surface `residuals` prominently
   ("questi residui sono tracciati come follow-up: …") — the post-run review that
   replaced the ~25 mid-run questions. If `degraded`, say so plainly (the run was
   incomplete and resumed).
5. **Record truthful telemetry — reconciled against disk (F-040).** Before appending `telemetry`
   to `${metricsDir}/skill-runs.jsonl`, fill the fields the workflow could not compute and
   **reconcile the report against the real disk state** (agent `reason` strings can over-claim — a
   residual may say "AC PASS / migration created" about a change a rollback later erased). Verify:
   every `perCardResults` entry marked `committed` actually has a commit in `${trunk}`
   (`git -C $MAIN log --oneline ${trunk} | grep <card>`); annotate any divergence and never present
   progress the disk does not show. Then fill `wall_clock_s` (now − kickoff `ts`) and
   `followups_on_disk` (count the actual follow-up files on disk in the main repo, NOT
   `residualFollowups.length` — which double-counts). **Cost (the A/B's whole point) — do NOT trust
   the workflow's `total_tokens`/`agent_count` as the headline figure.** They are **partial**:
   `total_tokens` is `budget.spent()` output-only AND the agent counters do not include the subagents
   spawned inside the nested workflows (`new2-resolve`, `new-final-review`) — on the real FEAT-0022 run
   the workflow reported `total_tokens=476k` / `agent_count=30` while the harness saw ~4.15M subagent
   tokens / 64 agents (≈8× under). So **always** run the `/new` Phase-8 `-stats` script to read the
   real transcript `usage` (not only when `total_tokens` is null), record it as the headline cost, and
   keep the workflow's figures clearly labelled as `total_tokens_workflow`/`agent_count_workflow`
   (partial, output-only, excludes nested workflows). Keep `degraded`/`degradation_reasons` +
   `cards_deferred_done_pending` in the record so
   the A/B comparison stays honest. Also record `migration_gate: <migration.status>`
   (`none`|`applied`|`skipped`|`degraded`) — the Step-3.5 gate is a pre-launch interaction, NOT a
   mid-batch question, so it does not break the zero-ask-during-batch invariant; logging it keeps the
   A/B honest about when a migration was front-loaded. Keep `deferral_breakdown` (per-class counts
   of WHY residuals became follow-ups instead of in-batch fixes) in the record — a class dominating
   it is a root-cause signal (many `out-of-ownership` → PRD MAY-EDIT too narrow · many `unresolved` →
   fixes genuinely hard · many `scope-expansion` → cards under-specified upstream), and it is the
   data to consult BEFORE proposing any change to the deferral logic. Keep `cross_card_integrated`
   too (count of residuals the pre-final-review Cross-Card Integration Pass implemented in-batch —
   out-of-ownership-within-batch + outage retries — instead of leaving as follow-ups); with
   `deferral_breakdown` it shows how many deferrals were genuinely undeferrable vs absorbed in-batch.
   Keep `ledger_reconciled` + `owner_gated_deduped` (v4.31.0) too — they quantify the ledger
   self-correction: `ledger_reconciled` > 0 means the workflow retracted residuals a later commit had
   already satisfied (work the skill used to suppress by hand; a persistently high value signals
   deferrals resolving too late — order the dependent card earlier), and `owner_gated_deduped` > 0
   means N defers were collapsed to one external action.
   Do NOT re-summarise the cards — the workflow already did.
