baldart 4.12.0 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,249 @@
1
+ <!-- Modulo on-demand di /new — NON un file installato a sé. Caricato via Read dalla § "Routing" del SKILL.md core. -->
2
+
3
+ > **Modulo `/new`** — eseguilo, poi torna al core § "Routing" per la fase successiva. I `§ "..."` (Context economy, Context Tracking, Trivial-card fast-lane, Risk-signal detector, Fix Application Log) vivono nel **core SKILL.md**.
4
+
5
+ ## Phase 0 — Workspace Hygiene Pre-flight (BLOCKING — non-skippable)
6
+
7
+ **Why this exists**: FEAT-0006 incident left the main repo with an unpushed orphan commit (`c9d41f9`) and `develop` diverged from `origin/develop` because `/new` started work on a dirty/diverged repo without surfacing the situation. This phase reconciles the main repo state BEFORE any worktree is created, and snapshots any in-progress user work so Phase 6c can restore it after the batch.
8
+
9
+ **Auto Mode does NOT override this phase.** Every `AskUserQuestion` below is non-bypassable — the model has no authority to pick an option on the user's behalf.
10
+
11
+ **Steps:**
12
+
13
+ 0. **Feature gate + config resolution (BLOCKING)** — before anything else:
14
+ - Read `features.has_backlog` from `baldart.config.yml`. If it is `false` (or the key is absent and the user confirms there is no backlog), this skill REFUSES to run: print "`/new` operates on backlog cards and requires `features.has_backlog: true` — run `npx baldart configure` to enable." and HALT. Do NOT proceed to step 1.
15
+ - Resolve `$TRUNK` = `git.trunk_branch` from `baldart.config.yml`. **When the key is absent** (consumer updated to ≥4.0.0 without re-running `configure`), do NOT hard-assume `develop` — autodetect the repo's real default branch exactly as worktree-manager does, so `/new` and `nw` agree on the base: `git -C "$MAIN" symbolic-ref --quiet refs/remotes/origin/HEAD` (strip `refs/remotes/origin/`), else the first existing local branch among `develop` / `main` / `master`. A `main`-trunk repo defaulted to `develop` here would diverge from the worktree base `nw` picks and break every `git diff "$TRUNK...HEAD"` gate. Only HALT ("Trunk branch unresolved — run `npx baldart configure`") if nothing resolves. Persist the resolved value as `Trunk branch:` in the tracker `## Worktree` section. **Every later Phase 0 / Phase 6c bash snippet that references the integration trunk MUST use `$TRUNK`, never a baked-in `develop`.** Begin every later consumer with a guard: if `$TRUNK` is empty → HALT with "Trunk branch unresolved — re-read `git.trunk_branch` from the tracker".
16
+ - Resolve `$METRICS` = `paths.metrics` from `baldart.config.yml` (default `docs/metrics`). This is the framework-owned telemetry directory written by Phase 8 (tracker archive, `skill-runs.jsonl`, `sessions/`). The dirty-tree gate (step 3) reads `$METRICS` to recognise — and never surface — its own telemetry output. Persist it as `Metrics dir:` in the tracker `## Worktree` section.
17
+
18
+ 1. **Resolve `$MAIN`** — the absolute path of the main repo (not a worktree). If `/new` was invoked from inside a worktree, walk up to the parent repo via `git rev-parse --show-superproject-working-tree` or `git worktree list` until you find the non-worktree root. Persist as `Main repo:` in the tracker `## Worktree` section. **Write `$MAIN` to the tracker the moment it is computed** — every later consumer (Phase 6c, Phase 6b) MUST re-read it from the tracker and HALT with "`$MAIN` absent from tracker" if the field is missing or empty, never silently use an undefined `$MAIN` (it does not survive context compaction).
19
+
20
+ 2. **Fetch remote state**:
21
+ ```bash
22
+ git -C "$MAIN" fetch origin --quiet
23
+ ```
24
+
25
+ 3. **Dirty-tree gate (BLOCKING — framework telemetry AND BALDART-managed artifacts are auto-ignored, never surfaced)** — capture the working tree state of the main repo, then **partition it** so the gate fires only on genuine in-progress user work:
26
+ ```bash
27
+ PORCELAIN="$(git -C "$MAIN" status --porcelain)"
28
+ # Drop two classes of framework-owned noise that are NOT user work:
29
+ # (a) telemetry THIS skill writes in Phase 8 (tracker archive, skill-runs.jsonl,
30
+ # sessions/) under $METRICS and never commits;
31
+ # (b) BALDART-managed install artifacts written by `baldart update`/`add`/`push`:
32
+ # .baldart/generated/ (overlay-merged agents/commands), .baldart/state.json
33
+ # (versioning ledger), .baldart/skill-conflicts.json. These ARE meant to be
34
+ # committed, but a reinstall/update leaves them dirty BEFORE the consumer has
35
+ # committed them — they are framework output, not feature work.
36
+ # NOTE: .baldart/overlays/ is deliberately NOT in this set — overlays are user-owned;
37
+ # an edited overlay IS genuine work and MUST still gate.
38
+ # Porcelain lines are "XY path"; paths with special chars are quoted. $METRICS from step 0.
39
+ USER_DIRTY="$(printf '%s\n' "$PORCELAIN" \
40
+ | grep -vE "^.{3}\"?${METRICS}/" \
41
+ | grep -vE "^.{3}\"?${METRICS}\"?$" \
42
+ | grep -vE "^.{3}\"?\.baldart/(generated/|state\.json|skill-conflicts\.json)" \
43
+ | grep -v '^[[:space:]]*$')"
44
+ ```
45
+ **Why**: Phase 8 copies the batch tracker into `$METRICS/archive/` and appends to `$METRICS/skill-runs.jsonl` *after* the merge, and never commits them. And `baldart update`/`add` regenerate `.baldart/generated/*` + bump `.baldart/state.json` on every framework sync — left uncommitted until the next reconcile. If either class tripped this gate, **every batch would block on the previous update's own output** — a self-inflicted loop. They are not user work and the user is never asked about them.
46
+ - If `$PORCELAIN` is non-empty but `$USER_DIRTY` is **empty** (only telemetry under `$METRICS` and/or BALDART-managed `.baldart/` artifacts are dirty) → do **NOT** gate. Write `Dirty: framework-managed-only (auto-ignored)` to the tracker and proceed to step 4. No `AskUserQuestion`.
47
+ - If `$USER_DIRTY` is **non-empty** (genuine uncommitted user work) → invoke `AskUserQuestion`:
48
+ - Question: `"Main repo ($MAIN) ha modifiche non committate prima di partire con la batch. Come procedo?"`
49
+ - Options (max 4):
50
+ 1. **"Stash automatico (restore in Phase 6c)"** — `$MAIN` is the main checkout (NOT a worktree), so a stash here is safe. Run `git -C "$MAIN" stash push -u -m "baldart-new-phase0-<FIRST-CARD-ID>-<timestamp>"` and write the **stash MESSAGE label** (`baldart-new-phase0-<FIRST-CARD-ID>-<timestamp>`) to the tracker under `## Workspace Snapshot: <message-label> (created <timestamp>)`. Phase 6c resolves the stash by this message — NEVER by a positional `stash@{N}`, because other stashes pushed during the batch (on the main checkout) would shift the index. Do NOT record `stash@{0}`.
51
+ 2. **"Committa adesso (apri editor)"** — halt the batch with a clear message asking the user to commit in their terminal and re-invoke `/new`. Do NOT proceed to step 4.
52
+ 3. **"Procedi senza stash (lavoro mio, lo gestisco io)"** — explicit user override. Log in tracker: `## Workspace Snapshot: dirty-tree override @ <timestamp> — user accepted responsibility`. Phase 6c will still check post-merge state but will NOT attempt restore.
53
+ 4. **"Abort batch"** — halt the batch, leave the tracker file in place, exit.
54
+
55
+ Do NOT silently proceed. Do NOT auto-stash without the user picking option 1.
56
+
57
+ 4. **Divergence gate (BLOCKING — framework-management commits do NOT count as orphan commits)** — compare local `$TRUNK` against `origin/$TRUNK` (the trunk resolved in step 0):
58
+ ```bash
59
+ read BEHIND AHEAD <<< "$(git -C "$MAIN" rev-list --left-right --count "origin/$TRUNK...$TRUNK")"
60
+ ```
61
+ `$BEHIND` / `$AHEAD` are the raw counts. Before branching, **reclassify the ahead commits**: commits produced by `baldart update`/`baldart add` (subtree merges into `.framework/`, the `[CHORE] baldart update …` commit, and the regenerated overlay files they carry) are *expected* divergence, not the FEAT-0006 orphan-commit pattern. Count only **genuine** unpushed commits:
62
+ ```bash
63
+ GENUINE_AHEAD=0; GENUINE_LIST=""; FW_SKIPPED=0
64
+ for sha in $(git -C "$MAIN" rev-list "origin/$TRUNK..$TRUNK"); do
65
+ subj="$(git -C "$MAIN" log -1 --format=%s "$sha")"
66
+ # subtree merge (e.g. "Merge commit '…' as '.framework'") or baldart update/add chore
67
+ if printf '%s' "$subj" | grep -qE "as '\.framework'" || printf '%s' "$subj" | grep -qiE "baldart (update|add)"; then
68
+ FW_SKIPPED=$((FW_SKIPPED+1)); continue
69
+ fi
70
+ # touches ONLY framework-managed paths? (empty file list = merge commit, handled above)
71
+ # - .framework/ (subtree payload)
72
+ # - .baldart/generated/, .baldart/state.json, .baldart/skill-conflicts.json
73
+ # (artifacts a reinstall/update commits: regenerated overlay files + version ledger)
74
+ # .baldart/overlays/ is intentionally EXCLUDED — an overlay edit is genuine user work.
75
+ files="$(git -C "$MAIN" show --pretty=format: --name-only "$sha" | grep -v '^$')"
76
+ if [ -n "$files" ] && ! printf '%s\n' "$files" | grep -qvE '^(\.framework/|\.baldart/(generated/|state\.json|skill-conflicts\.json))'; then
77
+ FW_SKIPPED=$((FW_SKIPPED+1)); continue
78
+ fi
79
+ GENUINE_AHEAD=$((GENUINE_AHEAD+1)); GENUINE_LIST="$GENUINE_LIST $sha"
80
+ done
81
+ ```
82
+ `$FW_SKIPPED` framework-management commits are auto-ignored (log them — see below). Branch on `$BEHIND` and the **genuine** ahead count `$GENUINE_AHEAD` (NOT the raw `$AHEAD`):
83
+
84
+ - **`BEHIND=0` and `GENUINE_AHEAD=0`** — synchronized for `/new`'s purposes. If `$FW_SKIPPED > 0`, write `Divergence: $FW_SKIPPED framework-management commits ahead (auto-ignored — baldart update/subtree)` to the tracker. **No `AskUserQuestion`.** Proceed to step 5.
85
+ - **`BEHIND>0` and `GENUINE_AHEAD=0`** (only behind) — invoke `AskUserQuestion`:
86
+ - Question: `"Local $TRUNK è behind origin/$TRUNK di $BEHIND commit. Come procedo?"`
87
+ - Options: `[Fast-forward pull adesso]` / `[Procedi senza pull]` / `[Abort]`.
88
+ - On `Fast-forward pull adesso`: if `$MAIN` HEAD == `$TRUNK`, run `git -C "$MAIN" pull --ff-only origin "$TRUNK"`; otherwise log "main HEAD is `<branch>` — fetch already updated `refs/remotes/origin/$TRUNK`, local `$TRUNK` ref will be reconciled in Phase 6c".
89
+ - **`BEHIND=0` and `GENUINE_AHEAD>0`** (genuine UNPUSHED LOCAL COMMITS, this is the FEAT-0006 pattern) — invoke `AskUserQuestion`:
90
+ - Question: `"Local $TRUNK è ahead di origin/$TRUNK di $GENUINE_AHEAD commit locali non pushati (esclusi $FW_SKIPPED commit di gestione framework). Cosa faccio?"`
91
+ - Show **only the genuine** commits inline: `git -C "$MAIN" show -s --oneline $GENUINE_LIST`.
92
+ - Options: `[Push adesso (git push origin $TRUNK)]` / `[Cherry-pick a parte e continua]` / `[Lascia così e procedi (lo gestisco io)]` / `[Abort]`.
93
+ - **`BEHIND>0` and `GENUINE_AHEAD>0`** (diverged both ways) — invoke `AskUserQuestion`:
94
+ - Question: `"Local $TRUNK è diverged da origin/$TRUNK: $BEHIND behind, $GENUINE_AHEAD genuine ahead. Servono entrambe le riconciliazioni. Come procedo?"`
95
+ - Options: `[Rebase local $TRUNK su origin/$TRUNK]` / `[Mostrami i commit e fammi decidere]` / `[Abort]`.
96
+
97
+ 5. **Log and proceed** — write to the tracker:
98
+ ```
99
+ ## Phase 0 — Workspace Hygiene Pre-flight
100
+ Status: PASS
101
+ Main repo: $MAIN
102
+ Trunk branch: $TRUNK
103
+ Dirty: <none | framework-managed-only (auto-ignored) | stashed: <message-label> | user-override>
104
+ Divergence (local…origin/$TRUNK): <0\t0 | framework-mgmt-only (auto-ignored: $FW_SKIPPED) | resolved: ff-pull | resolved: pushed | user-deferred>
105
+ Completed: <timestamp>
106
+ ```
107
+ If any step ended in HALT, set `Status: HALT` and stop — do NOT continue to `## Pre-flight (once)`.
108
+
109
+ 6. **Anti-bypass guard** — before exiting Phase 0, re-read the tracker section you just wrote. If `## Phase 0` is missing or shows `Status: HALT`, refuse to proceed. There is no `--skip-phase-0` flag; if you find yourself reaching for one, treat it as a self-correction trigger and stop.
110
+
111
+ ---
112
+
113
+ ## Pre-flight (once)
114
+
115
+ 1. Read each backlog card from `${paths.backlog_dir}/*.yml` to understand scope and dependencies. Also read the project's canonical-docs registry — typically `${paths.references_dir}/ssot-registry.md` plus any linking-protocol guide — to understand which canonical docs exist for the feature area being implemented. Exact filenames are listed in `.baldart/overlays/new.md`; skip when absent.
116
+ 1b. **Validate card fields (pre-flight gate)** — for each card, verify it has the minimum required fields before queuing it:
117
+ - `requirements` — must be a non-empty list (>=1 item)
118
+ - `acceptance_criteria` — must be a non-empty list (>=1 item)
119
+ - `files_likely_touched` — must be a non-empty list (>=1 file)
120
+ If any card fails: log the specific missing fields in `## Issues & Flags`, ask the user to fill them in before proceeding with that card, and continue pre-flight for any remaining valid cards.
121
+
122
+ 1c. **Field Registry Validation (pre-flight gate)** — for each card with a `data_fields` block, run the project's field-validation tool if available (path listed in `.baldart/overlays/new.md`; typically `python3 tools/validate-card-fields.py <card-yaml-path>`).
123
+ - If exit 1: display the field errors in `## Issues & Flags` and HALT — ask the user to fix the card before proceeding. Do not start implementation until the card passes validation.
124
+ - If the card has DB-index signals (`db_indexes` — or legacy `firestore_indexes` — or `data.collections`/`data.tables`) but NO `data_fields` block: log WARNING in `## Issues & Flags` — "Card `<ID>` touches the persistence layer but has no `data_fields` block. Field/column names are unvalidated."
125
+ - Cards with no `data_fields` and no storage signals: skip silently.
126
+ - If the project does not ship a field-validation tool: skip this step.
127
+ 2. Check `${paths.references_dir}/project-status.md` for current state (skip when absent).
128
+ 3. Determine which cards can run in **parallel** (no shared files/components) vs which must be **sequential** (dependencies or overlapping paths). Use `group.sequence` to determine execution order within a group.
129
+ 3b. **Build a file-ownership map** — for each card, enumerate every source file it is expected to touch (from `claimed_paths`, `paths`, and the implementation plan). Assign each file to **exactly one agent**. If two cards claim the same file, force those cards sequential on a single agent — do NOT spawn them in parallel. Record this map in the tracker under `## File Ownership Map`. This map is the authoritative source for all agent file permissions in Phase 2.
130
+ 3c. **Complexity assessment — team mode decision**
131
+
132
+ Determine whether to use **team mode** (parallel coder agents with isolated contexts) or keep **sequential mode** (current behavior).
133
+
134
+ **Decision logic:**
135
+
136
+ 1. Read `execution_strategy.recommended_mode` from the epic parent card (if it exists). If present, use it as the default. The `execution_strategy` block is authored by `prd-card-writer` with the canonical shape `groups:` (a list, each entry has `level:` (int) + `cards:` (list)) — consume that shape, not a flat `parallel_group` field.
137
+ 2. If no `execution_strategy` exists, compute:
138
+ - Count total cards in batch
139
+ - Count max cards in any single group (from `execution_strategy.groups[].cards`, i.e. cards sharing the same `level`)
140
+ - If no `execution_strategy.groups` exist, compute the levels on-the-fly: build dependency graph from `depends_on`/`blocks`, add conflict edges for cards sharing `(MODIFY)` files, compute topological layers via BFS — each topological layer becomes one group `level`.
141
+ 3. Apply threshold:
142
+ - **Sequential mode** if ANY of: total cards <= 3 — OR all cards are in different groups (max group size = 1, nothing to parallelize) — OR all cards form a linear dependency chain.
143
+ - **Team mode** if: total cards > 3 AND at least one group has 2+ cards.
144
+ 4. Log decision in tracker:
145
+ ```
146
+ ## Execution Mode
147
+ Mode: team | sequential
148
+ Reason: [e.g., "6 cards, 3 parallel groups, max 3 cards in group 1"]
149
+ ```
150
+ 5. Inform the user:
151
+ ```
152
+ Batch: N cards, M file unici
153
+ Gruppi paralleli: K livelli, max P card in parallelo
154
+ Modalita: **team mode** / **sequential mode** — [reason]
155
+ ```
156
+ Proceed without asking (the PRD already approved the strategy).
157
+
158
+ When `mode == sequential`, the per-card pipeline below runs exactly as documented. The `execution_strategy.groups` levels are simply ignored. When `mode == team`, skip the per-card pipeline and follow the **Team Mode** section at the end of this document.
159
+
160
+ **→ Create the Task spine now.** The execution mode and (in team mode) the wave layout are resolved — create the native Task spine per § "Progress Visibility" A: `Pre-flight` (→ `in_progress`) + one task per card (wave-labelled in team mode) + `Final review` + `Merge & cleanup`. Emit the first Progress Bar with this batch's table. Mark `Pre-flight` → `completed` once worktree setup (step 5) finishes.
161
+
162
+ 3d. **Codex batch cross-card grounding check** (runs in background during worktree setup)
163
+
164
+ > **Why**: a non-Anthropic frontier model (Codex, via `codex-companion.mjs`) reviews the full card batch for cross-card conflicts that per-card plan-auditor checks cannot detect (each plan-auditor sees only one card).
165
+
166
+ **Skip decision (provenance-aware — since v4.3.0).** The `/prd` Step 6.6 holistic audit (4-agent team + Codex adversarial pass) ALREADY ran this exact cross-card analysis over the cards when they were authored — its Codex prompt covers `files_likely_touched` conflicts, dependency shadows, implicit ordering, and shared-state mutation across the whole audited set. Re-running here is only worth the Codex call when **something changed between that audit and now**. Compute the skip before launching:
167
+
168
+ 1. **Always skip** if the batch has only 1 card (no cross-card conflicts possible).
169
+ 2. Otherwise, read `metadata.holistic_audit` from every card in the batch and evaluate the four SKIP conditions — **all must hold**:
170
+ - **S1 — provenance present**: every batch card has `metadata.holistic_audit` with non-empty `audited_at`, `audited_commit`, and `audited_set`. (Missing/partial on any card ⇒ condition fails.)
171
+ - **S2 — jointly audited**: all batch cards carry the **same** `audited_set` value (they were reviewed together, not stitched from separate PRD runs).
172
+ - **S3 — batch ⊆ audited set**: every batch card ID is present in that shared `audited_set`.
173
+ - **S4 — no drift on the claimed paths**: no commit touched any path the batch claims, between the audit baseline and the trunk this run grounds on. Using the shared `audited_commit` (`$AC`) and the batch's union of claimed/touched paths from the file-ownership map (step 3b, `$BATCH_PATHS`):
174
+ ```bash
175
+ # empty AC, or AC not in history → treat as drift (do NOT skip)
176
+ DRIFT="$(git -C "$MAIN" log --oneline "$AC".."$TRUNK" -- $BATCH_PATHS 2>/dev/null || echo "DRIFT")"
177
+ ```
178
+ S4 holds **iff** `$AC` is non-empty AND the command succeeds AND `$DRIFT` is empty.
179
+ 3. **If S1–S4 all hold → SKIP the Codex cross-card check.** Log in the tracker under `## Cross-Card Conflicts (Codex)`:
180
+ `SKIPPED (provenance) — batch ⊆ holistic_audit set <audited_set>, no drift since <AC short sha> (audited <audited_at>)`. Then proceed to step 4 with the file-ownership map unchanged. Do NOT present anything to the user — this is a non-decision.
181
+ 4. **Otherwise → RUN the check** (launch below). Record WHY in the same tracker section so the choice is auditable: `RUN — <reason>` where reason is one of `no/partial provenance` (S1) · `batch spans multiple audit sets` (S2) · `batch not a subset of audited set` (S3) · `drift on <first drifted path>` (S4).
182
+
183
+ `$MAIN` and `$TRUNK` are the same variables resolved in Phase 0. This gate degrades safely in every direction: any missing signal, ambiguity, or git error falls through to RUN — never to a silent skip.
184
+
185
+ Launch via `Bash` with `run_in_background: true` and `timeout: 300000`:
186
+
187
+ ```bash
188
+ AUDIT_FILE="/tmp/codex-crosscard-<FIRST-CARD-ID>-<SESSION-ID>.md" && \
189
+ CODEX_SCRIPT="$(ls -d ~/.claude/plugins/marketplaces/openai-codex/plugins/codex/scripts/codex-companion.mjs ~/.claude/plugins/cache/openai-codex/codex/*/scripts/codex-companion.mjs 2>/dev/null | sort -V | tail -1)" && \
190
+ [ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" > "$AUDIT_FILE" && exit 1; \
191
+ node "$CODEX_SCRIPT" task --wait "
192
+ Cross-card grounding check for a batch of backlog cards about to be implemented together.
193
+ Your job is to find conflicts BETWEEN cards that per-card reviewers would miss.
194
+
195
+ Cards to check (read each file):
196
+ ${CARD_PATHS}
197
+
198
+ File-ownership map:
199
+ ${FILE_OWNERSHIP_MAP}
200
+
201
+ Check:
202
+ 1. FILE CONFLICTS: Do two cards modify the same file in incompatible ways?
203
+ (e.g., Card A adds field X to interface Foo, Card B restructures Foo entirely)
204
+ 2. IMPLICIT DEPENDENCIES: Does Card A change a type/function that Card B's
205
+ requirements assume stays unchanged? Flag missing depends_on.
206
+ 3. EXECUTION ORDER RISKS: Given the execution_strategy group/level assignments, will parallel
207
+ execution cause merge conflicts or type errors?
208
+ 4. SHARED STATE MUTATIONS: Do multiple cards write to the same persistence
209
+ {entity} ({collection|table|item} per `stack.database`) in ways that could
210
+ conflict at runtime?
211
+
212
+ For each finding return:
213
+ - **Cards involved**: CARD-A + CARD-B
214
+ - **Conflict type**: FILE_CONFLICT | IMPLICIT_DEP | ORDER_RISK | STATE_MUTATION
215
+ - **Evidence**: exact field/file from each card
216
+ - **Fix**: concrete recommendation (add depends_on, force sequential, etc.)
217
+
218
+ If no cross-card conflicts: return PASS.
219
+ " > "$AUDIT_FILE" 2>&1
220
+ ```
221
+
222
+ **Variable interpolation**:
223
+ - `${CARD_PATHS}`: newline-separated list of all `- ${paths.backlog_dir}/FEAT-XXXX-*.yml` paths in the batch
224
+ - `${FILE_OWNERSHIP_MAP}`: the file-ownership map built in step 3b
225
+
226
+ > `<SESSION-ID>` is the current session id (e.g. `$CLAUDE_CODE_SESSION_ID`, or a run UUID if unset). The task-scoped unique name prevents two concurrent `/new` sessions on the same day from clobbering each other's findings (a date-only name silently collides). Record the exact `$AUDIT_FILE` path in the tracker under `## Cross-Card Conflicts (Codex)` so the result-handling step reads the SAME path — never re-derive it by wildcard/timestamp.
227
+
228
+ **Result handling** (read before Phase 1 of first card):
229
+ - **Background completion barrier (BLOCKING):** record the background task id when you launch it; do NOT read `$AUDIT_FILE` until that task has completed. Because this gate's verdict steers Phase-1 card ordering, the first card MUST NOT start while the check is in flight.
230
+ - **TIMED_OUT branch:** the launch sets `timeout: 300000` (5 min). If the background task hits the timeout without producing a terminal result (the tail of `$AUDIT_FILE` shows no `PASS` / conflict block / `CODEX_NOT_FOUND`), treat it as **TIMED_OUT** — do NOT leave the task "in-progress" and silently proceed. Log `cross-card-check: TIMED_OUT` in `## Cross-Card Conflicts (Codex)` and take the SAME fallback as `CODEX_NOT_FOUND`: spawn `code-reviewer` over the batch with the four conflict questions. Never start the batch with cross-card review in an unresolved/in-flight state.
231
+ - Read the exact `$AUDIT_FILE` path recorded in the tracker after the background command completes.
232
+ - If the file contains **`CODEX_NOT_FOUND`** (Codex unavailable): do NOT silently proceed — **fallback**: spawn the `code-reviewer` agent over the full batch's card YAMLs + file-ownership map with the same cross-card conflict questions (FILE_CONFLICT / IMPLICIT_DEP / ORDER_RISK / STATE_MUTATION). If `code-reviewer` is also unavailable, surface `CAPABILITY_UNAVAILABLE: cross-card-review` to the user and ask whether to proceed without cross-card detection or halt. Never run a multi-card batch with cross-card review silently skipped.
233
+ - If **PASS** or file empty: proceed normally.
234
+ - If **conflicts found**: log in tracker under `## Cross-Card Conflicts (Codex)` and present to user. For each conflict:
235
+ - `FILE_CONFLICT` / `ORDER_RISK` → force the conflicting cards sequential (update file-ownership map).
236
+ - `IMPLICIT_DEP` → add `depends_on` entry to tracker notes (do NOT modify backlog YAML).
237
+ - `STATE_MUTATION` → add warning to both cards' Phase 2 briefings.
238
+
239
+ 4. **Worktree setup** — delegate to the **worktree-manager** skill (`/nw` in programmatic mode):
240
+ a. **Resolve the `slug`** (required by the `/nw` programmatic API — `{ cards, groupParent, slug, branch? }`). Derive it deterministically: if the parent card (or the lead card) has `git_strategy.branch` set, parse the slug from it (`feat/<PARENT-ID>-<slug>` → `<slug>`); otherwise slugify the parent/lead card `title` (lowercase, non-alphanumerics → `-`, collapse repeats, trim, cap ~40 chars). Persist the resolved `slug` in the tracker `## Worktree` section so the path/branch are reproducible across compaction. Do NOT let `/nw` invent its own slug — pass it explicitly.
241
+ b. Pass all card IDs, their `group.parent` fields, AND the resolved `slug` to the skill's grouping logic.
242
+ c. The skill handles: grouping cards by `group.parent`, deriving branch names from `git_strategy.branch` (falling back to `feat/<PARENT-ID>-<slug>` using the slug you passed), creating the worktree in `.worktrees/`, installing dependencies, copying env files, assigning a free port, and verifying the build.
243
+ d. The skill updates `.worktrees/registry.json` with the worktree entry (including all card IDs in the `cards` field).
244
+ e. If build fails → the skill STOPs and reports. Do NOT continue.
245
+ f. Record the worktree path, branch, slug, and port from the skill's output in the tracker.
246
+ 5. **Tracker already exists** — the `/tmp/batch-tracker-<FIRST-CARD-ID>.md` file was created at batch start (before Phase 0, see "Context Tracking"). Here, backfill the `## Worktree` section with the worktree path, branch, slug, and port resolved in step 4, AND write `Created: <ISO-8601 now>` (`date -u +%Y-%m-%dT%H:%M:%SZ`) — this is the strategy-independent start anchor Phase 8's `cycle_time_mins` reads. Do NOT re-create the file (Phase 0 has already written to it).
247
+ 6. Create a task list to track progress across all cards.
248
+
249
+ ---
@@ -0,0 +1,253 @@
1
+ <!-- Modulo on-demand di /new — NON un file installato a sé. Caricato via Read dalla § "Routing" del SKILL.md core. -->
2
+
3
+ > **Modulo `/new`** — eseguilo, poi torna al core § "Routing" per la fase successiva. I `§ "..."` (Context economy, Context Tracking, Trivial-card fast-lane, Risk-signal detector, Fix Application Log) vivono nel **core SKILL.md**.
4
+
5
+ ## Team Mode (parallel coder agents with isolated contexts)
6
+
7
+ When the complexity assessment (step 3c) selects team mode, the orchestrator changes role: instead of executing each card's pipeline sequentially, it coordinates parallel coder agents — each with its OWN isolated context window.
8
+
9
+ **Key principle**: the orchestrator stays LEAN. It holds only:
10
+ - The tracker file path
11
+ - Parallel group status (pending/active/done)
12
+ - Completion verdicts per card (pass/fail + files changed)
13
+
14
+ It does NOT accumulate implementation details, codebase-architect findings, or review outputs — those live and die in each agent's isolated context.
15
+
16
+ ### Team Mode Pre-flight
17
+
18
+ After the standard pre-flight (steps 1-7), add:
19
+
20
+ 1. Read the `execution_strategy.groups` (each with `level` + `cards`) and sort into execution layers by `level`. For legacy cards lacking the block, fall back to the on-the-fly topological-layer computation from step 3c.
21
+ 2. Update tracker with team mode section:
22
+ ```
23
+ ## Team Mode
24
+ Status: active
25
+
26
+ ## Parallel Groups
27
+ | Group | Cards | Status |
28
+ |-------|-------|--------|
29
+ | 0 | FEAT-01 | pending |
30
+ | 1 | FEAT-02, FEAT-03 | pending |
31
+ | 2 | FEAT-04, FEAT-05 | pending |
32
+ ```
33
+
34
+ ### Per-Group Execution
35
+
36
+ Process groups in order (0, 1, 2, ...). Within each group, spawn coder agents IN PARALLEL — one per card.
37
+
38
+ #### Step A: Pre-compute shared context (ONCE per group)
39
+
40
+ Before spawning coders, the orchestrator runs **codebase-architect** ONCE for the entire group (not per card). This single call covers all cards in the group.
41
+
42
+ Prompt:
43
+ ```
44
+ Explore the codebase for context relevant to these cards:
45
+ [list card IDs + their scope.summary, one line each]
46
+
47
+ Focus on: [combined files_likely_touched from all cards in group]
48
+ Return: file paths, type signatures, existing patterns. Max 30 lines.
49
+ ```
50
+
51
+ This is the ONLY context the orchestrator accumulates per group. After passing it to the coders, it can be purged.
52
+
53
+ **Persist for review reuse (since v3.35.0)** — also write these findings to
54
+ `/tmp/arch-baseline-group-<FIRST-CARD-ID>.md`. D.4b's per-card `/codexreview` lean contract points
55
+ its `arch_baseline_path` at this file, so the review reuses the group baseline instead of re-spawning
56
+ `codebase-architect`.
57
+
58
+ #### Step B: Spawn parallel coder agents
59
+
60
+ **→ Visibility (wave change)**: this is a new wave starting. TaskUpdate ALL of this group's card spine tasks → `in_progress`, and emit a Progress Bar with the new `Wave <X>/<Y>` header per § "Progress Visibility".
61
+
62
+ For each card in the current group, spawn a coder agent using the Agent tool. ALL agents for the group MUST be spawned in a **SINGLE message** (multiple Agent tool calls) to run truly in parallel.
63
+
64
+ Each coder agent receives a **SELF-CONTAINED** mission briefing that includes EVERYTHING it needs — it will NOT call codebase-architect or plan-auditor itself:
65
+
66
+ ```
67
+ Agent tool call:
68
+ subagent_type: "coder"
69
+ mode: "bypassPermissions"
70
+ run_in_background: true
71
+ name: "coder-<CARD-ID>"
72
+ prompt: |
73
+ ## AUTONOMOUS CARD IMPLEMENTATION — <CARD-ID>
74
+
75
+ You are implementing this card AUTONOMOUSLY. Complete ALL phases below
76
+ without external coordination. You have your own isolated context.
77
+
78
+ ### 1. Card Specification (verbatim)
79
+ Requirements:
80
+ [copy from card YAML]
81
+
82
+ Acceptance Criteria:
83
+ [copy from card YAML]
84
+
85
+ ### 2. Codebase Context (pre-computed)
86
+ [paste codebase-architect findings from Step A]
87
+
88
+ ### 3. Working Directory
89
+ All work MUST happen in the worktree: <worktree-path>
90
+ cd to this directory before any file operations.
91
+
92
+ ### 4. File Permissions (ENFORCED)
93
+ MAY EDIT:
94
+ [files from ownership map for THIS card only]
95
+
96
+ FORBIDDEN:
97
+ - ALL files not in the MAY EDIT list
98
+ - Do NOT create files outside the designated paths
99
+
100
+ ### 5. Design Reference (if UI card)
101
+ [path to design.html if exists]
102
+
103
+ ### 6. Your Pipeline
104
+ Execute these steps in order:
105
+ a) Print the numbered requirements checklist (anti-skip measure)
106
+ b) Implement ALL requirements
107
+ c) Run: npx tsc --noEmit && npx eslint --max-warnings=0 <your-files>
108
+ d) Self-heal up to 3 times if checks fail
109
+ e) Verify completeness: for each requirement, confirm code exists (read it)
110
+ f) If any requirement is missing after implementation, implement it now
111
+ g) Output the completion report (MANDATORY format below)
112
+
113
+ ### 7. Completion Report (MANDATORY)
114
+ ```completion-report
115
+ card: <CARD-ID>
116
+ status: done | partial | blocked # card-level — matches coder.md four-state (coder never self-emits deferred-approved; the orchestrator sets that after the AC-Closure Gate)
117
+ requirements:
118
+ - id: 1
119
+ text: "[text]"
120
+ status: done | not_implemented # per-requirement is BINARY (legacy row-level partial/blocked were silent-deferral channels — removed)
121
+ evidence: "file:line"
122
+ files_changed:
123
+ - path/to/file.ts
124
+ build_status: pass | fail
125
+ lint_status: pass | fail
126
+ tsc_status: pass | fail | n/a # n/a when stack.language excludes typescript
127
+ retry_count: N
128
+ ```
129
+ ```
130
+
131
+ #### Step C: Wait for group completion
132
+
133
+ The orchestrator waits for ALL background agents in the group to complete. It will be notified automatically as each finishes (`run_in_background`).
134
+
135
+ > **Do NOT poll with `sleep N; echo "waiting..."` loops.** Background agents (and background `Bash` commands) re-invoke the orchestrator automatically when they finish — issuing `sleep`/`echo` "waiting" turns burns orchestrator turns and tokens for zero progress. Simply end your turn after spawning the background work; you will be woken on completion. This applies to EVERY barrier in Step D (D.1 build, D.2 reviewers, D.3/D.3b agents, D.4 qa-sentinel, D.4a doc-reviewer, D.4b `/codexreview`), not just Step C.
136
+
137
+ For each completed agent:
138
+ 1. Read the completion report from the agent's output.
139
+ 2. Log to tracker: card ID, status, files changed, build/lint status.
140
+ 3. Do NOT read or store implementation details — only the verdict.
141
+
142
+ **If an agent fails** (status: failed after 3 retries — the central repair cap):
143
+ - Log failure in tracker `## Issues & Flags`.
144
+ - Other agents in the group continue unaffected.
145
+ - After group completes, ask user: retry failed card or skip?
146
+ - **Retry re-entry (defined path):** on "retry", re-run the failed card from **Step B** (re-spawn the autonomous coder with a fresh briefing) — NOT from Step A, because the Step A arch context for the group is already in hand and is reused. The retried card then rejoins the group's Step D pipeline and MUST pass the SAME mandatory per-card sub-steps as its peers (D.3a AC-Closure → D.3b Simplify → D.3c E2E → D.4 QA → D.4a doc → D.4b codex → D.5 commit → D.6 backlog); there is no shortcut. The Step D coverage assertion will block Step E until the retried card has all mandatory tracker entries — so a retried card cannot silently skip a gate. **Cap: one Step-B re-entry per card** (consistent with the central cap discipline); on a second failure, re-ask with only skip/abandon so the loop cannot recur unbounded.
147
+
148
+ #### Step D: Post-group review + QA (ALL sub-steps MANDATORY)
149
+
150
+ > **The sub-steps below are ALL MANDATORY.** The previous lean Step D (build → combined review → qa → codex → commit) was an incident-causing shortcut (FEAT-0006: 10 sub-cards committed with 0 invocations of Phase 2.5b / 2.55 / 2.6 / 3 / 3.5 / 3.7) and is now FORBIDDEN. Every card in the group MUST complete every per-card sub-step (D.3a, D.3b, D.3c, D.4a) before the group reaches D.5 commit. Skipping any sub-step "to save time", "to save tokens", "because the diff is small", or for any model-invented reason is a protocol violation. Auto Mode does NOT override this.
151
+
152
+ After ALL agents in the group complete successfully:
153
+
154
+ 1. **D.1 — Build verification (group)** — Run `npm run build` in the worktree to verify combined changes compile (redirect to `/tmp/build-group.txt` per § "Context economy"; surface only exit code + bounded extract on failure). If build fails, identify which card's changes broke it (from `git diff --name-only` per card), spawn a targeted fix-coder for those files only.
155
+
156
+ 1.5. **D.1.5 — Effective per-card review profile (compute ONCE; drives D.2 + D.4b)** — For EACH card in the group, compute its **effective codex profile** with the SAME deterministic rule the sequential Phase 3.7 Step C uses, so the two paths never disagree:
157
+ - **Floor**: read the card's `review_profile` field (`skip`/`light`/`balanced`/`deep`) per the QA Profile Selector (fallback-computed only for legacy cards lacking the field).
158
+ - **Escalation-only (Step A detector)**: run the Phase 3.7 **Step A** high-risk detector (bash + grep) on THIS card's committed diff (`git diff "$TRUNK...HEAD" -- <card files from ownership map>`). A matched trigger promotes `light`→`full`; it can NEVER downgrade `full`→`light`. The card's `review_profile` is the floor; the detector is the safety net on top.
159
+ - **Partition** the group into two lists and log them in the tracker under `## Team Mode`:
160
+ - `LIGHT_CARDS` = cards whose effective profile is `light` or `skip` **AND** zero Step-A triggers.
161
+ - `FULL_CARDS` = all others (effective profile `balanced`/`deep`, OR any Step-A trigger).
162
+ - **Sub-classify `TRIVIAL_CARDS` ⊆ `LIGHT_CARDS`** = cards that are `IS_TRIVIAL` on the committed diff (§ "Trivial-card fast-lane": `review_profile == skip` AND 0 Step-A triggers AND **non-source diff**). These are the LIGHT cards that have nothing for `code-reviewer` to review. (A `skip` card whose diff DID touch a source file is in `LIGHT_CARDS` but NOT `TRIVIAL_CARDS` — the guard keeps it on the code-review path.)
163
+ - **Sub-classify `DOC_DEFER_CARDS`** (since v4.7.0, for #2 doc deferral) = cards with `review_profile == light` whose committed diff touches **NO documentation file** (no `.md`, no path under `${paths.references_dir}`, no data-model/ssot/api doc). Their per-card doc-review is deferred to the Final F.3 doc-reviewer. (Trivial cards, and any card whose diff touches a doc file, are NOT in this set — doc-review stays relevant for them.)
164
+ - Log: `## D.1.5 Effective Profiles\n<CARD-ID>: profile=<floor> triggers=<n> diff=<source|non-source> → effective=<light|full> (<LIGHT_CARDS|FULL_CARDS>)<, TRIVIAL / DOC_DEFER if applicable>` per card. This single computation is the SSOT for D.2 (code-reviewer + doc-reviewer scoping), D.3b/D.3c (already skipped for trivial), and D.4b (inclusion) — do NOT recompute it downstream.
165
+
166
+ 2. **D.2 — Combined static review (group)** — Two reviewers, **scoped by the D.1.5 partition** so each card gets exactly ONE per-card/group code review proportional to its risk (the other is the Final FULL gate):
167
+ - **doc-reviewer — over the group MINUS `DOC_DEFER_CARDS`** (since v4.7.0). It runs **read-only here** (it cannot write while code-reviewer reads in parallel — parallel-safety), MUST **attribute every doc finding to a specific card** (by file → ownership map), and applies the full Phase 3 mandate INCLUDING the spec/docs-drift→bug lens (since v3.35.0). The `DOC_DEFER_CARDS` (light, no-doc diff per D.1.5) are excluded — their doc-review is deferred to the Final F.3 doc-reviewer (batch-wide). **If the group is entirely `DOC_DEFER_CARDS` → skip the D.2 doc-reviewer** and log `D.2 doc-reviewer: DEFERRED to Final FULL gate (all cards light + no-doc diff)`. D.4a consumes the per-card findings (for the non-deferred cards) and dispatches the doc-reviewer (now alone, in write mode) to apply them — no second AUDIT spawn, but the FIXES are still owned by doc-reviewer.
168
+ - **code-reviewer — scoped to the diff-union of `LIGHT_CARDS` MINUS `TRIVIAL_CARDS`** (run it in parallel with the doc-reviewer over those files). These light non-trivial cards skip D.4b, so D.2 is their single per-card code review (the cross-batch Codex pass at Final covers them adversarially). **`TRIVIAL_CARDS` are excluded from the code-reviewer scope** — their diff is non-source, so there is nothing to code-review (doc-reviewer still covers them via the whole-group pass above; the Final FULL gate covers them adversarially). **If `LIGHT_CARDS \ TRIVIAL_CARDS` is empty → do NOT spawn code-reviewer at D.2** (every remaining card is either `FULL_CARDS` — deeper review at D.4b — or `TRIVIAL_CARDS` — nothing to review). Log the deterministic gate reason: `D.2 code-reviewer: scope=[<ids>] | excluded-trivial=[<ids>] | SKIPPED (no code-bearing light cards)`.
169
+ - **Tradeoff (documented, accepted — see top-of-file `REVIEW DEPTH SCALES` clause)**: for `FULL_CARDS`, cross-card detection moves from the per-group D.2 pass to the per-batch **Final-review FULL gate** (Codex over the entire batch diff, plus code-reviewer fallback) — same merge-gate safety, feedback arrives at batch-end rather than per-group. This is the intended de-duplication: `FULL_CARDS` are NOT re-reviewed by a group-level code-reviewer on top of their D.4b `/codexreview`.
170
+
171
+ 3. **D.3 — Apply fixes (group)** — If D.2 findings exist, spawn ONE fix-coder to apply all fixes in a single pass. Run build + lint after.
172
+
173
+ 3a. **D.3a — Phase 2.5b AC-Closure Gate (per-card, BLOCKING — non-skippable)** — For EACH card in the group, **sequentially**, invoke the full Phase 2.5b gate as documented in `### Phase 2.5b — AC-Closure Gate (BLOCKING — Scope Closure Discipline)`. This includes: build the AC Closure Ledger from the card YAML, run the rationalization scan, invoke `AskUserQuestion` one-per-deferred-AC, run the `implementation_notes` deferral audit, and persist the ledger in the tracker. Until EVERY card in the group exits PASS, do NOT proceed to D.3b. Cards exiting with `not_implemented` ACs that the user routes to "Implementa adesso" must finish their fix-coder loop and re-pass the gate before D.3b starts for the next card. Log under `## AC Closure Ledger — <CARD-ID>` per card.
174
+
175
+ 3b. **D.3b — Phase 2.55 Simplify (per-card, FANNED OUT across the group)** — The Simplify agents are **read-only analysis on file-disjoint per-card diffs** (the orchestrator applies the fixes afterward), so there is NO reason to run them one card at a time. **Spawn the per-card Simplify analysis for ALL eligible cards in PARALLEL** — in a SINGLE message, fire each card's Phase 2.55 trio (Reuse / Quality / Efficiency) against that card's diff captured to `/tmp/diff-<CARD-ID>.txt` (per Phase 2.55 step 2 — pass each trio the **path**, scoped to the card's File Ownership Map; never inline the diff). Per-card (not group-aggregate) so findings stay attributable. When all analyses return, **apply fixes per card** (file-disjoint → no write conflict), then re-run `npm run lint` and `npx tsc --noEmit` on the worktree ONCE for the whole group (redirect to disk per § "Context economy"). (Concurrency is capped by the platform; passing N cards is safe — excess agents queue.)
176
+ - **Gate (enumerated, `review_profile`-driven)**: SKIP D.3b for a card whose `review_profile == skip` (trivial / non-implementable card — Simplify is quality-only, so there is no merge-gate coverage to lose, and there is no substantive diff to simplify). Log `simplify: SKIPPED (review_profile=skip)`. For `light`/`balanced`/`deep` cards D.3b runs unchanged. This is the ONLY enumerated skip — never skip D.3b "for time" on a `light`+ card. (Skipped cards are simply omitted from the parallel fan-out.)
177
+
178
+ 3c. **D.3c — Phase 2.6 E2E-Review (per-card)** — First, evaluate the existing Gate table for EVERY card at once (skip when `features.has_e2e_review: false`, backend-only diff per the diff predicate documented in Phase 2.6, or card type in the Phase 2.6 skip set — `backend`/`api`/`db`/`infra`/`docs`/`chore`/`config`). In practice most cards in a group skip this gate (backend/db/api), so the eligible set is usually 0–1. For the cards that PASS the gate, invoke `/e2e-review` in programmatic mode with that card's payload. Each `/e2e-review` keeps its own isolated state dir (`.baldart/e2e-review/<CARD-ID>/`), so multiple runs do not clobber each other's artifacts.
179
+ - **Parallel-when-safe**: if **two or more** cards pass the gate, you MAY fan them out in parallel ONLY when they hit **disjoint routes/pages** — the genuinely shared resource is the worktree's single dev-server port, and concurrent Playwright sessions against one server are fine for disjoint routes. If the eligible cards touch overlapping routes (or `/e2e-review` spins its own server and a port clash is possible), run those **sequentially** to avoid a flaky cross-test. Default to parallel for the common disjoint case; fall back to sequential on any contention.
180
+ - BLOCKING per-card: if `/e2e-review` returns `"blocked"` or `"error"`, surface to the user via the same `AskUserQuestion` documented in Phase 2.6 — do NOT proceed to D.4 with an unresolved card. Skips are logged with the documented gate reason, never with `"time budget"` or similar.
181
+
182
+ 4. **D.4 — QA gate (group; since v4.7.0 — runs only for `deep` / risk-escalation, else deferred to Final)** — Read each card's `review_profile` field and the D.1.5 Step-A trigger result. **Run the group qa-sentinel (once, at FULL) iff** the group's MAX profile is `deep` **OR** any card in the group had a Step-A risk escalation. **Otherwise (max profile ≤ `balanced`, no escalation) → DEFER the group QA to the Final Review F.3 qa-sentinel** (FULL suite + build + audit over the entire batch — the unconditional merge gate); log `D.4 QA: DEFERRED to Final FULL gate (group max=balanced, no risk escalation)`. This mirrors sequential step 21b. When it DOES run, invoke qa-sentinel at FULL (the combined group diff must be validated together) using the same prompt contract as Phase 3.5 step 22. ⚠️ A balanced-only group runs its first suite at the Final gate; merge safety is preserved because Final is FULL over the whole batch.
183
+
184
+ 4a. **D.4a — Per-card doc gate (consumes D.2, since v3.35.0; doc-reviewer-applied since v3.40.0)** — Do NOT re-run the doc AUDIT (D.2 already produced per-card-attributed findings). If any card in the group has doc findings, invoke the **doc-reviewer once in write mode** over the group, passing the per-card-attributed findings from D.2, to APPLY all doc fixes in a single pass (it is now alone — code-reviewer is done — so the D.2 parallel-safety constraint no longer applies). Do **NOT** spawn a fix-coder for doc findings: `doc` is owned by `doc-reviewer` (see "Domain-Override Domains"); a code-oriented coder lacks the doc-invariant contract. The only exception is a doc-drift→bug finding rooted in CODE — that follows the D.4b code fix path. (Previously D.4a spawned a fix-coder per card; the audit was already collapsed to a single attributed D.2 pass. D.4b's per-card `/codexreview` also skips its doc-reviewer via the lean contract, so the doc AUDIT runs once per group while the doc FIXES run once per group via doc-reviewer.) **Telemetry** — append one row per applied doc finding to `## Fix Application Log`: `D.4a | doc | est_lines=<n> | decision=doc-reviewer | applied_by=doc-reviewer | card=<ID> | finding=<1-line>`. **Phase-8 producer (named counter)** — ALSO record per card the `doc_gaps: found=<N> fixed=<M>` line in that card's `## Completed Cards` entry (same named counter as sequential Phase 3 step 15), so Phase 8 reads `doc_gaps_found`/`doc_gaps_fixed` from a structured field, not a free-form row.
185
+
186
+ 4b. **D.4b — Pre-Merge Codex Review Gate (per-card, profile-gated via D.1.5)** — Invoke `/codexreview` for **EACH card in `FULL_CARDS`** (the partition computed at D.1.5), one at a time, BEFORE any commit. This mirrors Phase 3.7 of the sequential path.
187
+ - **`LIGHT_CARDS` → SKIP D.4b** (enumerated `review_profile`-driven gate reason, NOT a time skip). A `light`/`skip` 0-trigger card already received its single per-card code review at the **D.2 group pass**, and its Codex-adversarial review is **guaranteed by the unconditional Final-review FULL gate** (Codex over the entire batch diff, post-batch). Running `/codexreview` here at `light` would only re-run `code-reviewer` + FP-gate (Codex is dropped at `light` since v3.38.0) — a pure duplicate of D.2. Log per card: `codex-review: SKIPPED (light, 0 triggers — D.2 group code-review covered + Codex adversarial guaranteed by Final FULL gate)`.
188
+ - **`FULL_CARDS` → run `/codexreview` as today** (the per-card Codex adversarial + CoVe + FP-gate pass is exactly where the per-card code review for these cards lives — D.2 deliberately did NOT re-review them). The profile passed is always `full` (D.1.5 already resolved it; do NOT recompute). Keep the sequential one-at-a-time loop (avoid N concurrent `/codexreview`, each of which fans out multiple sub-agents → rate-limit risk).
189
+ Apply the same fix sub-loop as sequential Phase 3.7 Step C.4: if the consolidated report shows verified BLOCKER/HIGH findings, spawn a fix-coder and — **re-writing the consumed-once lean contract first** — re-invoke `/codexreview` via the Skill tool with `args: <CARD-ID>` (max 2 retries per card; a bare prose mention or a missing card-ID would let the retry review the wrong card). If still BLOCKER/HIGH after retries, ask the user before proceeding to D.5. The D.5 commits MUST NOT happen until every card in the group has a PASS verdict (or explicit user override via `AskUserQuestion`). Log results in the tracker under `## Pre-Merge Codex Review` per card. **Lean + profile (since v3.35.0)**: before each card's `/codexreview`, apply the same Review Profile Selector and write the same `/tmp/codexreview-lean-<CARD-ID>.json` contract as sequential Phase 3.7 Step C — `arch_baseline_path` pointing at `/tmp/arch-baseline-group-<FIRST-CARD-ID>.md`, `skip_doc_reviewer: true`, `skip_api_perf_auditor: true` (since v4.7.0 — api-perf deferred to the Final F.3 batch-wide auditor), and `profile: full` (every card that reaches D.4b is in `FULL_CARDS` per D.1.5 — `light`/`skip` 0-trigger cards were already partitioned out and skip D.4b entirely; do NOT recompute the profile here). `full` runs the standard pipeline (Codex adversarial + CoVe + FP-gate, minus the duplicate doc-reviewer). The merge-gate safety for the skipped `LIGHT_CARDS` is the post-batch **Final-review FULL gate** (a single FULL `/codexreview` over the entire batch diff, which team mode reaches via "Post-batch — same as sequential mode"). To make D.4b run for every card again (pre-v4.5.0 behavior), drop the D.1.5 partition and iterate over all group cards here at their per-card profile; the final full gate stays regardless.
190
+
191
+ 5. **D.5 — Commit** — One commit per card using explicit staging from the ownership map. **NO stash in worktrees** (stashes are globally shared via `refs/stash` — see Phase 4 WORKTREE COMMIT RULE):
192
+ ```bash
193
+ cd <worktree-path>
194
+ # For each card in the group:
195
+ git add <card's-files-only>
196
+ # Disambiguate "nothing to commit" from a hook rejection BEFORE committing:
197
+ if [ -z "$(git status --porcelain)" ]; then
198
+ echo "D.5 <CARD-ID>: nothing staged — already committed upstream; record HEAD and skip"
199
+ else
200
+ git commit -m "[CARD-ID] Brief description"
201
+ fi
202
+ ```
203
+ If `git commit` itself fails with a non-empty staging area (a pre-commit / lint-staged hook rejected it), apply the SAME bounded handler as sequential Phase 4 step 27: clear a stale `COMMIT_LOCK`, re-stage explicitly, retry at most **2 times**, then log `[COMMIT-BLOCKED]` and escalate via `AskUserQuestion` — never loop unbounded and never silently leave a card uncommitted.
204
+
205
+ 6. **D.6 — Update backlog (MANDATORY — do NOT skip)** — For EACH card in the group:
206
+ a. Edit the backlog YAML (`${paths.backlog_dir}/<CARD-ID>.yml`): set `status: DONE`, add `completed_date: <today>`, add implementation notes (NEVER include `[USER-APPROVED DEFERRAL]` lines that didn't actually pass through D.3a's gate).
207
+ b. **Verify the write**: re-read the YAML file and confirm `status: DONE` is present. If not, retry.
208
+ c. Stage the updated YAML and include it in the card's commit (or as an immediate follow-up commit).
209
+ d. Log in tracker: `card_status: DONE (verified)` for each card.
210
+ e. **→ Visibility**: TaskUpdate each card's spine task → `completed` (strip any live phase suffix) as it reaches DONE here.
211
+ Note: Phase 6b (Status Reconciliation) will catch any card missed here, but aim for zero misses.
212
+
213
+ #### Step D coverage assertion (MANDATORY end-of-group check)
214
+
215
+ Before moving to Step E, the orchestrator MUST verify the tracker contains, for EACH card in the group, ALL of the following entries (or an explicit gate-skip log with the documented reason):
216
+
217
+ - `## AC Closure Ledger — <CARD-ID>` with `ac-closure: implemented=N | user-approved deferrals=M | follow-up cards created=K` (NEVER skipped — applies to trivial cards too)
218
+ - `simplify: <N fixes | clean — 0 fixes | SKIPPED (review_profile=skip)>` (per-card from D.3b)
219
+ - `e2e-review: <status>` (with documented gate-skip reason if SKIP)
220
+ - `doc-review: <status | DEFERRED to Final FULL gate (DOC_DEFER_CARDS: light + no-doc diff)>` (from D.4a — runs for trivial cards too; the DEFERRED form is valid ONLY for `DOC_DEFER_CARDS` per D.1.5)
221
+ - `qa: <profile=... | verdict=... | mechanical-only (trivial) | DEFERRED to Final FULL gate (group max=balanced, no risk escalation)>` (group-level from D.4; the DEFERRED form is valid when the group max profile ≤ balanced with no Step-A escalation)
222
+ - `api-perf: <covered at D.4b | DEFERRED to Final FULL gate (skip_api_perf_auditor)>` (per-card — `skip_api_perf_auditor` defers it to F.3 batch-wide; DEFERRED is the normal v4.7.0 value)
223
+ - `code-review: <covered at D.2 | covered at D.4b | SKIPPED (trivial — non-source diff)>` (per-card — the trivial SKIP is valid ONLY for `TRIVIAL_CARDS` per the D.1.5 partition)
224
+ - `codex-review: <verdict | SKIPPED (light, 0 triggers — D.2 group code-review covered + Final FULL gate) | SKIPPED (trivial — non-source diff; covered by Final FULL gate)>` (per-card from D.4b — the SKIPPED forms are valid ONLY for `LIGHT_CARDS` / `TRIVIAL_CARDS` respectively)
225
+
226
+ A missing entry means a sub-step was skipped. An entry whose value is a **`review_profile`-driven SKIP/DEFER**, an **`IS_TRIVIAL` SKIP**, or a **`/prd`-provenance SKIP** with a documented enumerated reason above (D.3b `skip` profile; D.4b `LIGHT_CARDS`; code/codex `TRIVIAL_CARDS`; doc-review `DOC_DEFER_CARDS`; QA `group max=balanced, no escalation`; api-perf `skip_api_perf_auditor`; plan-auditor `holistic_audit provenance`) is a VALID, present entry — not a violation; all defer to the unconditional Final FULL gate. What remains forbidden: a missing entry, or a skip whose reason is `time budget` / `to save tokens` / any model-invented constraint. If any entry is genuinely missing, do NOT proceed to Step E — return to the missing sub-step and execute it. Documenting "skipped per time budget" or similar is a protocol violation per the top-of-file rigidity clause.
227
+
228
+ #### Step E: Context purge + next group
229
+
230
+ After committing all cards in the group:
231
+ 1. Update tracker: move group to done, log all results per card.
232
+ 2. **PURGE**: forget all implementation details, review findings, architect context.
233
+ 3. **→ Visibility**: emit a Progress Bar reflecting the wave boundary (this wave done; next `Wave <X+1>/<Y>` pending) per § "Progress Visibility".
234
+ 4. Move to the next pending group (Step A again).
235
+
236
+ ### Sequential fallback within team mode
237
+
238
+ If two cards in the same parallel group are discovered at runtime to have a file conflict (e.g., one coder created an unexpected file that overlaps):
239
+ 1. Detect via file-diff gate after Step C.
240
+ 2. Revert the later card's conflicting files.
241
+ 3. Re-run that card as a standalone sequential step after the group.
242
+
243
+ ### Dependency gates between groups
244
+
245
+ Before starting group N, verify ALL cards in groups 0..N-1 are status: done. If any card in a previous group failed and was skipped:
246
+ - If cards in group N `depends_on` it: skip those dependent cards too, log in `## Issues & Flags`.
247
+ - If no dependency: proceed normally.
248
+
249
+ ### Post-batch (same as sequential mode)
250
+
251
+ After all groups are complete, run the same Final Review, Phase 6 (merge), and Phase 7 (production readiness) as documented above. Since v3.37.0 the Final Review runs a **single FULL `/codexreview` over the entire batch diff** (per the Final-review FULL gate) — no scope reduction — so every team-mode card, including any reviewed at `light` in D.4b, receives a guaranteed full review before merge.
252
+
253
+ ---
@@ -977,8 +977,14 @@ if [ "$CURRENT_BRANCH" = "$TRUNK" ]; then
977
977
  # (v3.39.0 — the finalizer MUST conclude). The cause is almost always an
978
978
  # uncommitted append to the framework-owned telemetry log left by a prior run.
979
979
  # Partition the dirty tree:
980
- # - framework-owned artifact (${paths.metrics}/skill-runs.jsonl) → auto-reconcile
981
- # (commit + rebase) so the ff completes with zero data loss;
980
+ # - framework-owned artifacts → auto-reconcile (commit + rebase) so the ff
981
+ # completes with zero data loss. Two sub-classes:
982
+ # (a) telemetry: ${paths.metrics}/skill-runs.jsonl
983
+ # (b) BALDART-managed install output left by `baldart update`/`add`/`push`:
984
+ # .baldart/generated/ (overlay-merged agents/commands), .baldart/state.json
985
+ # (version ledger), .baldart/skill-conflicts.json — these ARE meant to be
986
+ # committed; a reinstall just leaves them uncommitted until the next sync.
987
+ # .baldart/overlays/ is NOT owned here — an overlay edit is genuine work.
982
988
  # - ANY foreign file → emit a decision marker the orchestrator MUST convert
983
989
  # into ONE explicit user gate. Never auto-commit work this run did not own.
984
990
  METRICS_LOG="${paths.metrics}/skill-runs.jsonl" # paths.metrics default: docs/metrics
@@ -988,22 +994,24 @@ if [ "$CURRENT_BRANCH" = "$TRUNK" ]; then
988
994
  for f in $DIRTY; do
989
995
  case "$f" in
990
996
  "$METRICS_LOG") OWNED="$OWNED $f" ;;
997
+ .baldart/generated/*|.baldart/state.json|.baldart/skill-conflicts.json) OWNED="$OWNED $f" ;;
991
998
  *) FOREIGN="$FOREIGN $f" ;;
992
999
  esac
993
1000
  done
994
1001
  if [ -n "$FOREIGN" ]; then
995
1002
  echo "[SYNC-NEEDS-DECISION] main repo $TRUNK cannot fast-forward; foreign uncommitted files:${FOREIGN} — orchestrator MUST raise ONE explicit user gate (commit / user-handles), never a passive note."
996
1003
  elif [ -n "$OWNED" ]; then
997
- # Only framework-owned telemetry is dirty reconcile autonomously, lossless.
998
- git -C "$MAIN" add "$METRICS_LOG"
999
- git -C "$MAIN" commit -m "chore(metrics): reconcile skill-runs telemetry before $TRUNK sync" --quiet
1004
+ # Only framework-owned artifacts (telemetry + BALDART-managed install output) are
1005
+ # dirty reconcile autonomously, lossless.
1006
+ git -C "$MAIN" add $OWNED
1007
+ git -C "$MAIN" commit -m "chore(baldart): reconcile framework-managed artifacts before $TRUNK sync" --quiet
1000
1008
  if git -C "$MAIN" pull --rebase origin "$TRUNK" 2>/dev/null; then
1001
1009
  git -C "$MAIN" push origin "$TRUNK" 2>/dev/null \
1002
- && echo "✅ Reconciled stale metrics log + synced $TRUNK to origin." \
1003
- || echo "✅ Reconciled stale metrics log (local $TRUNK 1 commit ahead; syncs on next push). Tree clean."
1010
+ && echo "✅ Reconciled framework-managed artifacts + synced $TRUNK to origin." \
1011
+ || echo "✅ Reconciled framework-managed artifacts (local $TRUNK 1 commit ahead; syncs on next push). Tree clean."
1004
1012
  else
1005
1013
  git -C "$MAIN" rebase --abort 2>/dev/null || true
1006
- echo "[SYNC-NEEDS-DECISION] metrics rebase conflict on $TRUNK — orchestrator MUST raise ONE explicit user gate."
1014
+ echo "[SYNC-NEEDS-DECISION] framework-managed reconcile rebase conflict on $TRUNK — orchestrator MUST raise ONE explicit user gate."
1007
1015
  fi
1008
1016
  else
1009
1017
  echo "[SYNC-NEEDS-DECISION] main repo $TRUNK cannot fast-forward and the working tree is clean (diverged?) — orchestrator MUST raise ONE explicit user gate."