baldart 4.5.0 → 4.7.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.7.0] - 2026-06-03
9
+
10
+ **`/new` smette di rifare per-card 4 review che la Final FULL gate già ripete sull'intero batch.** La Final Review F.3 gira sempre, incondizionata, su tutto il diff di batch: Codex + **doc-reviewer** + **api-perf-cost-auditor** + **qa-sentinel** (suite completa + build + audit). Quindi le passate *per-card* di quegli stessi reviewer sono, per la sicurezza del merge-gate, già coperte dalla rete finale — il loro unico valore residuo è il fail-fast/attribuzione. Quattro pruning, tutti deterministici e con la Final come rete: (1) **plan-auditor grounding** saltato (sequential) quando `/prd` ha già fatto l'holistic audit (`metadata.holistic_audit`) e non c'è drift sui path della card — mirror esatto del gate v4.3.0 Step 3d; (2) **doc-review per-card** deferita alla Final per le card `light` il cui diff non tocca file di documentazione; (3) **qa-sentinel per-card** che gira solo per `deep` (o `balanced` escalata da risk-drift) — `balanced` non-rischiose deferiscono la suite alla Final; (4) **api-perf-cost-auditor per-card** droppato via nuovo flag lean-contract `skip_api_perf_auditor`, deferito alla Final. **MINOR** (comportamento `/new` più lean; nessuna chiave `baldart.config.yml` — si appoggia su `review_profile` + `metadata.holistic_audit` già esistenti).
11
+
12
+ > **Why.** Il criterio è netto: si potano solo le review che la **Final FULL gate rifà** (doc, api-perf, qa, codex). Ciò che la Final NON copre — **AC-Closure** (scope discipline), **Simplify** (quality/reuse), **codebase-architect grounding**, **E2E** — NON si tocca: pruneare quelli sarebbe perdere copertura, non togliere ridondanza. Ogni skip è un gate-reason **enumerato e deterministico** (provenance `/prd`, oppure `review_profile`), mai un `time budget`. ⚠️ **Tradeoff #3 (esplicito)**: la maggior parte delle card `feature`/`enhancement` è `balanced` per Rule C, quindi un batch tutto-balanced esegue il primo run della suite di test solo alla Final gate — si perde il fail-fast/attribuzione per-card; il merge-gate resta salvo (Final = suite completa sull'intero batch). Reversibile in 1 riga (ripristina `balanced → SCOPED`). Il percorso sequenziale e quello team restano allineati (stessa logica di defer). `/codexreview` riceve un campo lean-contract simmetrico a `skip_doc_reviewer` (api-perf è un breadth-agent indipendente, NON un validatore del FP-gate → safe).
13
+
14
+ ### Changed
15
+
16
+ - **`framework/.claude/skills/new/SKILL.md`** — (1) Phase 1 step 4: skip provenance-based del plan-auditor (P1 holistic_audit presente + P2 no-drift `git log <audited_commit>..<trunk> -- <card paths>`; fail-safe → RUN). (2) Phase 3 + team D.1.5/D.2/D.4a: nuova sotto-classe `DOC_DEFER_CARDS` (light + diff senza doc) esclusa dal doc-reviewer, deferita alla Final. (3) Phase 3.5 step 21b + team D.4: `balanced` deferisce qa-sentinel alla Final (eccetto risk-escalation → FULL per-card); solo `deep`/escalated gira per-card. (4) lean-contract a Phase 3.7 Step C + D.4b: `skip_api_perf_auditor: true`. + Step D coverage assertion (accetta i nuovi defer come entry valide) + clausola in testa (enumera i nuovi gate-reason).
17
+ - **`framework/.claude/commands/codexreview.md`** — Step -0.5 + Step 2 lean-agent note: nuovo campo `skip_api_perf_auditor` che omette agent #2 (`api-perf-cost-auditor`) anche a `full`. Non tocca il FP-gate (dipende da `code-reviewer`, non da api-perf).
18
+
19
+ ## [4.6.0] - 2026-06-03
20
+
21
+ **`/new` ora ha una corsia "trivial" per le card minime: niente review di codice su un diff che non contiene codice.** Dopo il de-dup v4.5.0 (profondità scalata su `review_profile`), restava un pavimento alto: una card `skip`-profile ma implementabile — un fix di copy in un `.md`, un update di una riga di `ssot-registry`, un bump di config non-API — passava comunque per codebase-architect + plan-auditor + code-reviewer + AC-closure + QA + doc + Final. Una nuova **fast-lane** scatta quando `IS_TRIVIAL(card)` = `review_profile == skip` **AND** 0 trigger del detector Step-A **AND** diff **non-source** (check deterministico per estensione, riusando il predicato "backend-only" di Phase 2.6 — solo `.md`/`.json`/`.yml`/`.txt`/`.csv`). Una card trivial esegue solo il tail minimo sicuro: `coder → gate meccanici inline (markdownlint/lint/build) → AC-closure → doc-review → commit`, saltando **codebase-architect + plan-auditor + code-reviewer + simplify + Codex + la suite di test QA**. Vale in **entrambe le modalità** (sequential: gate in Phase 1 step 2c + 2.55/3.5/3.7; team: sotto-classe `TRIVIAL_CARDS ⊆ LIGHT_CARDS` esclusa dallo scope del code-reviewer a D.2). **MINOR** (nuova capability per-card; nessuna chiave `baldart.config.yml` — si appoggia su `review_profile` già autorato in PRD).
22
+
23
+ > **Why.** `review_profile: skip` NON è riservato agli epic: `prd-card-writer.md § Rule C` lo assegna deterministicamente a card `docs`/`chore`/`config` o puramente cosmetiche (typo/rename/copy) senza logica. È quindi un segnale autorato in PRD, persistito nello YAML, su cui ancorare la corsia **senza inventare una soglia a righe** (coerente col principio "data-driven sopra threshold arbitrarie"). Il classificatore è un AND a 3 condizioni con **guard fail-safe**: un solo file source nel diff, un trigger Step-A, o un profilo non-`skip` → `IS_TRIVIAL=false` e la card torna al percorso normale. La triviality può solo **togliere review a una card che non ha codice da revisionare**, mai il contrario — una `skip` mis-autorata su codice, o una il cui testo cita `auth`/`payment`, viene sempre ricatturata. Gli invarianti restano: **AC-closure** (scope discipline) e **doc-review** non si saltano mai, e la **Final Review F.3** copre incondizionatamente ogni card trivial nel gate cross-batch prima del merge (stessa rete su cui si appoggia già il percorso `light`). Tutti gli skip sono gate-reason enumerati deterministici, mai `time budget`.
24
+
25
+ ### Changed
26
+
27
+ - **`framework/.claude/skills/new/SKILL.md`** — (a) nuova sotto-sezione SSOT "Trivial-card fast-lane" (classificatore `IS_TRIVIAL` a 3 condizioni AND + guard + tabella di cosa salta/resta). (b) Clausola in testa: `IS_TRIVIAL` aggiunto all'elenco dei gate-reason enumerati. (c) Sequential Phase 1: nuovo step **2c** che salta codebase-architect + plan-auditor (step 3/3a/4) per card provvisoriamente trivial; il briefing del coder degrada a card-spec + target file. (d) Phase 2.55/3.5/3.7: gate `IS_TRIVIAL` ri-confermato sul diff reale → skip Simplify + QA-suite + Codex, gate meccanici inline; carve-out esplicito nell'"UNCONDITIONAL" di Phase 3.7. (e) Team D.1.5: sotto-classe `TRIVIAL_CARDS ⊆ LIGHT_CARDS`; D.2 esclude le trivial dallo scope del code-reviewer. (f) Step D coverage assertion: skip trivial come entry valide documentate. Non toccati: `codexreview.md`, `prd-card-writer.md`, AC-closure, doc-review, Final Review F.3, percorso light/full di v4.5.0.
28
+
8
29
  ## [4.5.0] - 2026-06-03
9
30
 
10
31
  **`/new` Team Mode non revisiona più lo stesso diff fino a tre volte: la profondità della code-review ora scala col `review_profile` della card.** Lo Step D del team mode faceva passare ogni card "full" sotto code-review tre volte — `D.2` (code-reviewer di gruppo) → `D.4b` (`/codexreview` per-card, che rispawna code-reviewer + Codex + CoVe + FP-gate) → Final Review F.3 (Codex sull'intero batch) — e ogni card "light" due volte (D.2 + un D.4b che a `light` esegue solo code-reviewer + FP, puro doppione di D.2). Un nuovo step **D.1.5** calcola UNA volta il profilo effettivo per card (floor da `review_profile` + escalation-only dal detector Step-A sul diff reale) e partiziona il gruppo in `LIGHT_CARDS` / `FULL_CARDS`. **D.2** ora esegue il code-reviewer solo sull'union dei diff `LIGHT_CARDS` (skippato del tutto se non ce ne sono); **D.4b** gira `/codexreview` solo per i `FULL_CARDS`, mentre i `LIGHT_CARDS` lo saltano (la loro review adversarial è garantita dalla Final FULL gate, sempre on). Esito: ogni card riceve **una sola** code-review per-card/gruppo proporzionale al rischio + la Final batch gate — light: D.2 + Final; full: D.4b + Final (giù da 3). **D.3b Simplify** salta sulle card `review_profile == skip` (quality-only, niente diff sostanziale). Tutti gli skip sono **gate-reason enumerati e deterministici** (driven dal campo `review_profile` autorato in PRD), non skip "per time budget": una nuova clausola "REVIEW DEPTH SCALES WITH `review_profile`" in testa alla skill lo formalizza. Eliminato anche il polling `sleep N; echo "waiting..."` ad ogni barrier (i background agent re-invocano l'orchestratore automaticamente). **MINOR** (cambia il comportamento di review di `/new` team mode senza rimuovere agenti o rompere install; nessuna chiave `baldart.config.yml` nuova — si appoggia su `review_profile` già esistente nella card).
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.5.0
1
+ 4.7.0
@@ -48,7 +48,8 @@ For the (single) card in scope, check for `/tmp/codexreview-lean-<CARD-ID>.json`
48
48
  "profile": "light" | "full",
49
49
  "arch_baseline_path": "/tmp/arch-baseline-<CARD-ID>.md",
50
50
  "diff_summary_path": "<completion-report or git-diff path>",
51
- "skip_doc_reviewer": true
51
+ "skip_doc_reviewer": true,
52
+ "skip_api_perf_auditor": true
52
53
  }
53
54
  ```
54
55
 
@@ -59,6 +60,11 @@ For the (single) card in scope, check for `/tmp/codexreview-lean-<CARD-ID>.json`
59
60
  - `skip_doc_reviewer: true` → **omit agent #3 (`doc-reviewer`)** in Step 2. Doc concerns are covered
60
61
  by `/new` Phase 3, which runs `doc-reviewer` (with the spec/docs-drift lens) on the same diff
61
62
  immediately before this gate. *(A2)*
63
+ - `skip_api_perf_auditor: true` (since v4.7.0) → **omit agent #2 (`api-perf-cost-auditor`)** in Step 2,
64
+ EVEN at `profile: "full"`. The api-perf/cost pass is deferred to the **Final Review F.3
65
+ api-perf-cost-auditor**, which runs batch-wide before merge — so a per-card run here would be a
66
+ duplicate. It is an independent breadth agent (NOT a Step 3 FP-gate validator), so omitting it is
67
+ safe (unlike `code-reviewer`, which the FP-gate depends on). *(A3)*
62
68
  - `profile: "light"` → ALSO omit agent #2 (`api-perf-cost-auditor`),
63
69
  **agent #4 (Codex adversarial)** (since v3.38.0), and **skip Step 3.5 (CoVe)**. Only agent #1
64
70
  (`code-reviewer`) and the Step 3 false-positive gate run. The Codex adversarial pass is the
@@ -154,11 +160,13 @@ Launch these agents in parallel for each card:
154
160
  > requires. Gate-running for the card happens in the QA flow, not in this deep-review parallel set.
155
161
 
156
162
  > **Lean agent set (Step -0.5)**: when a contract file is active, launch only the agents the resolved
157
- > mode permits — `skip_doc_reviewer` omits #3 (`doc-reviewer`); `profile: light` additionally omits #2
158
- > (`api-perf-cost-auditor`) AND **#4 (Codex adversarial)** (since v3.38.0). At `light`, only agent #1
159
- > (`code-reviewer`) launches (+ the Step 3 FP-gate). At `full` (and in full mode with no contract
160
- > file), launch all four (Codex #4 included). The standalone `/codexreview <CARD-ID>` invocation (no
161
- > contract) is always full.
163
+ > mode permits — `skip_doc_reviewer` omits #3 (`doc-reviewer`); `skip_api_perf_auditor` omits #2
164
+ > (`api-perf-cost-auditor`) **even at `full`** (since v4.7.0 deferred to the Final F.3 batch-wide
165
+ > auditor); `profile: light` additionally omits #2 AND **#4 (Codex adversarial)** (since v3.38.0). At
166
+ > `light`, only agent #1 (`code-reviewer`) launches (+ the Step 3 FP-gate). At `full` with
167
+ > `skip_api_perf_auditor`, launch #1 + #4 (Codex) (+ #3 unless `skip_doc_reviewer`). At `full` with no
168
+ > skips (and in full mode with no contract file), launch all four. The standalone
169
+ > `/codexreview <CARD-ID>` invocation (no contract) is always full with the complete set.
162
170
 
163
171
  **Codex invocation rules (agent #4):**
164
172
 
@@ -13,7 +13,7 @@ description: >
13
13
 
14
14
  > **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.
15
15
 
16
- > **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`, **and the card's `review_profile`-driven review depth — see next paragraph**). 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**.
16
+ > **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**.
17
17
 
18
18
  > **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** this means a `light`/`skip` (0-trigger) card receives its single per-card code review at the **D.2 group pass** and defers Codex-adversarial to the unconditional **Final-review FULL gate** (so D.4b is skipped for it), while a `full` card receives its per-card code review at the **D.4b `/codexreview`** pass (so the D.2 group code-reviewer does not re-review it). Every card still gets ≥1 per-card/group code review **plus** the cross-batch Final FULL gate — coverage is preserved, redundancy is removed. The **sequential** per-card pipeline is unchanged (it has no D.2 group code-reviewer, so its Phase 3.7 `/codexreview` stays the single per-card code review). Skipping a gate WITHOUT an enumerated `review_profile`/Gate-table reason remains a protocol violation.
19
19
 
@@ -388,6 +388,63 @@ disagree.
388
388
 
389
389
  ---
390
390
 
391
+ ## Trivial-card fast-lane (since v4.6.0 — SSOT; phases below CITE this, never redefine it)
392
+
393
+ Some cards are genuinely too small to justify the review machine: a `docs`/`chore`/`config`
394
+ card, a copy fix in a `.md`, a one-line `ssot-registry` update, a non-API `.yml` bump. Running
395
+ codebase-architect + plan-auditor + code-reviewer + Codex + the QA test suite on a diff that
396
+ contains **no source code** is pure waste — there is nothing for those agents to review. The
397
+ fast-lane routes such cards through the minimal safe tail. It is a **per-card** property
398
+ (applies in BOTH sequential and team mode), and it is the polar opposite of a `time budget`
399
+ skip: it is gated entirely on deterministic, PRD-authored signals.
400
+
401
+ ### The classifier — `IS_TRIVIAL(card)` (ALL three must hold — AND)
402
+
403
+ 1. **`review_profile == skip`** — read verbatim from the card YAML. Per `prd-card-writer.md § Rule C`,
404
+ `skip` is assigned to `docs`/`chore`/`config` cards, all-non-logic-file cards, and pure-cosmetic
405
+ cards (typo/rename/copy/wording/style). This is NOT the epic guard (an epic is never implemented;
406
+ a trivial card IS implemented, just with a minimal tail). **AND**
407
+ 2. **Zero Step-A high-risk triggers** — run the Phase 3.7 **Step A** detector (the same bash+grep:
408
+ high-risk module from `paths.high_risk_modules` / dead-code resurrection / reference-aliasing) on
409
+ this card's diff. Any trigger ⇒ NOT trivial. **AND**
410
+ 3. **Non-source diff** — `git diff --name-only` (working-tree pre-commit in sequential; `$TRUNK...HEAD`
411
+ post-commit in team mode) contains **NO file matching the source-extension predicate**
412
+ (reuse/extend the Phase 2.6 backend-only predicate):
413
+ ```bash
414
+ SRC_RE='\.(tsx?|jsx?|mjs|cjs|vue|svelte|css|scss|py|go|rs|java|rb|php|sql|prisma)$'
415
+ if echo "$CHANGED" | grep -qE "$SRC_RE"; then IS_TRIVIAL=0; else IS_TRIVIAL=1; fi
416
+ ```
417
+ Only `.md` / `.json` / `.yml` / `.yaml` / `.txt` / `.csv` and doc paths qualify.
418
+
419
+ **Fail-safe guard (degrade toward MORE review, never less)**: if ANY condition fails — a single
420
+ source file in the diff, one Step-A trigger, or a non-`skip` profile — `IS_TRIVIAL=false` and the
421
+ card follows its normal path (in team mode that is `LIGHT_CARDS`: D.2 code-reviewer + Final; in
422
+ sequential, the full per-card pipeline). A mis-authored `skip` on a code card, or a `skip` card
423
+ whose text mentions `auth`/`payment`/etc., is therefore always caught. The classifier can only ever
424
+ *remove* review from a card that demonstrably has no code to review.
425
+
426
+ ### What a trivial card runs vs skips
427
+
428
+ | Step | Trivial card |
429
+ |------|--------------|
430
+ | codebase-architect grounding (Phase 1 step 3) | **SKIP** (non-source, self-contained) |
431
+ | plan-auditor grounding (Phase 1 step 4) | **SKIP** (depends on architect findings) |
432
+ | coder (Phase 2) | **RUN** — briefing degrades to card-spec + target file from `files_likely_touched` (no architect section) |
433
+ | mechanical gates | **RUN INLINE** — `markdownlint` on changed `.md`, `lint` on lintable files, `build` as a sanity check (NO qa-sentinel spawn, NO test suite) |
434
+ | Phase 2.5b / D.3a AC-Closure | **RUN** (scope discipline, inline, cheap — never skipped) |
435
+ | Phase 2.55 / D.3b Simplify | **SKIP** |
436
+ | Phase 2.6 / D.3c E2E | **SKIP** (already gated by `docs`/`chore`/`config` type) |
437
+ | Phase 3 / D.4a doc-review | **RUN** (the relevant reviewer for docs/ssot) |
438
+ | Phase 3.5 / D.4 QA test suite | **SKIP** (covered by inline mechanical gates above) |
439
+ | Phase 3.7 / D.4b Codex | **SKIP** |
440
+ | commit + backlog | **RUN** |
441
+ | **Final Review F.3** | **RUNS (unconditional net)** — covers every trivial card in the batch-wide gate before merge |
442
+
443
+ Every skip above is logged with the enumerated reason `trivial: review_profile=skip + non-source
444
+ diff + 0 triggers` — a deterministic, card-authored gate reason. Never `time budget`.
445
+
446
+ ---
447
+
391
448
  ## Agent Routing (Phase 2 dispatcher)
392
449
 
393
450
  Phase 2 reads the card's `owner_agent` field and dispatches to the matching
@@ -437,9 +494,19 @@ For each card, execute these phases in order:
437
494
  - If NOT `DONE` → HALT: log in `## Issues & Flags` and ask the user: "Card <CARD-ID> depends on <DEP-ID> which is `<status>`. Proceed anyway, or wait?" Do not start implementation until the user responds explicitly. **The card status is NOT written until this gate passes** — so a HALT leaves the card untouched (no stale `IN_PROGRESS` for the next run to mis-read).
438
495
  - If `DONE` (or the user chose "proceed anyway") → continue.
439
496
  2b. **Claim** — only now set the card status to `IN_PROGRESS` and assign yourself.
440
- 3. Invoke the **codebase-architect** agent (MUST per AGENTS.md) to understand the relevant codebase area, existing patterns, and architecture before any implementation. When `features.has_lsp_layer: true`, the architect uses LSP find-references for identifier-shaped lookups this needs NO handoff from the orchestrator: the architect reads `features.has_lsp_layer` from `baldart.config.yml` directly (the flag is ambient) per `agents/code-search-protocol.md`. The orchestrator does NOT propagate the flag. (Earlier doc versions numbered this step 4; the step that read project-status BEFORE the architect was removed because it persisted pre-analysis context see step 3a.)
497
+ 2c. **Trivial-card classification (BLOCKING gate for steps 3–4)** evaluate `IS_TRIVIAL(card)` per § "Trivial-card fast-lane". Note: condition 3 (non-source diff) cannot be fully evaluated until the coder has produced the diff, so at this point compute the **provisional** trivial flag from conditions 1+2 only (`review_profile == skip` AND no Step-A trigger sourced from the card YAML text + `files_likely_touched` extensions — if EVERY path in `files_likely_touched` is non-source, condition 3 is provisionally satisfied). If provisionally trivial → **SKIP steps 3, 3a, and 4** (architecture grounding); log `trivial: architecture grounding skipped (review_profile=skip + non-source files_likely_touched + 0 triggers)` and jump to Phase 2. Re-confirm `IS_TRIVIAL` on the ACTUAL committed diff at the review gates (Phase 2.55/3.5/3.7); if the coder unexpectedly touched a source file, the guard flips the card back onto the normal review path there. If NOT provisionally trivial run steps 3, 3a, 4 as normal.
498
+ 3. **(skip when provisionally trivial — see 2c)** Invoke the **codebase-architect** agent (MUST per AGENTS.md) to understand the relevant codebase area, existing patterns, and architecture before any implementation. When `features.has_lsp_layer: true`, the architect uses LSP find-references for identifier-shaped lookups — this needs NO handoff from the orchestrator: the architect reads `features.has_lsp_layer` from `baldart.config.yml` directly (the flag is ambient) per `agents/code-search-protocol.md`. The orchestrator does NOT propagate the flag. (Earlier doc versions numbered this step 4; the step that read project-status BEFORE the architect was removed because it persisted pre-analysis context — see step 3a.)
441
499
  3a. Update `${paths.references_dir}/project-status.md` Active Code Context (skip when the file does not exist in the project) — do this AFTER the codebase-architect run (step 3) so the "Active Code Context" reflects the architect's findings (which files are actually in scope), not just the card YAML's `files_likely_touched`. Writing it before the architect run would persist pre-analysis claims that downstream agents (e.g. a parallel card) would then read as truth.
442
- 4. **Plan-auditor grounding check** — invoke the **plan-auditor** agent in **QUICK mode** (pass `mode: QUICK`; its contract runs only the grounding checks, and because the codebase-architect findings are passed in below it does NOT re-spawn codebase-architect for this narrow check):
500
+ 4. **Plan-auditor grounding check** — but first, a **provenance skip (since v4.7.0 mirror of Step 3d)**: the `/prd` Step 6.6 holistic audit already ran a per-card grounding pass when the card was authored. Re-grounding here is only worth a plan-auditor spawn if something changed since. Skip the plan-auditor when **BOTH** hold:
501
+ - **P1 — provenance present**: the card has `metadata.holistic_audit` with non-empty `audited_at`, `audited_commit`, `audited_set`.
502
+ - **P2 — no drift on this card's claimed paths** since the audit baseline. With `$AC` = `metadata.holistic_audit.audited_commit`, `$MAIN`/`$TRUNK` from the tracker, and this card's `files_likely_touched`/claimed paths (`$CARD_PATHS`):
503
+ ```bash
504
+ # empty AC, AC not in history, or any git error → treat as drift (do NOT skip)
505
+ DRIFT="$(git -C "$MAIN" log --oneline "$AC".."$TRUNK" -- $CARD_PATHS 2>/dev/null || echo "DRIFT")"
506
+ ```
507
+ P2 holds **iff** `$AC` is non-empty AND the command succeeds AND `$DRIFT` is empty.
508
+
509
+ (No S2/S3 cross-card conditions — grounding is per-card, and the holistic audit grounded each card individually.) If **P1 ∧ P2 → SKIP** the plan-auditor: log `plan-auditor grounding: SKIPPED (holistic_audit provenance, no drift on claimed paths since <AC short sha>)`, carry the card requirements unchanged into Phase 2, and proceed to step 5. **Fail-safe**: missing/partial provenance, any drift, or any git error → fall through to RUN the plan-auditor as written below (never a silent skip). Independent of the trivial fast-lane (a trivial card already skipped steps 3–4 at step 2c). Otherwise — invoke the **plan-auditor** agent in **QUICK mode** (pass `mode: QUICK`; its contract runs only the grounding checks, and because the codebase-architect findings are passed in below it does NOT re-spawn codebase-architect for this narrow check):
443
510
  ```
444
511
  mode: QUICK
445
512
  Grounding check only (NOT a full audit — do not run the full AUDIT CHECKLIST A-H, and do not
@@ -1090,6 +1157,8 @@ Domains NOT listed here remain governed by the per-phase rules of the correspond
1090
1157
 
1091
1158
  ### Phase 2.55 — Simplify (code cleanup before review)
1092
1159
 
1160
+ > **Trivial fast-lane gate**: re-confirm `IS_TRIVIAL` on the ACTUAL committed diff (§ "Trivial-card fast-lane" — all 3 conditions, now including the real non-source diff check). If trivial → **SKIP this phase** AND Phase 3.5 QA + Phase 3.7 Codex; instead run the **inline mechanical gates** (`markdownlint` on changed `.md`, `lint` on lintable changed files, `build` as a sanity check — no qa-sentinel, no test suite), then proceed to Phase 3 (doc review, which DOES run) and Phase 4 (commit). Log `simplify/qa/codex: SKIPPED (trivial — non-source diff)`. If the actual diff turned out to contain a source file → NOT trivial → run this phase and the normal review path. AC-Closure (Phase 2.5b) already ran and is never skipped.
1161
+
1093
1162
  After completeness is verified, clean up the implementation before it reaches reviewers and E2E tests. This phase launches three parallel agents on the card's diff, then applies fixes directly.
1094
1163
 
1095
1164
  **Step-by-step**:
@@ -1224,6 +1293,8 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1224
1293
 
1225
1294
  > **Note**: Code review is NOT performed in this phase — it is handled by the **mandatory unconditional `/codexreview` gate in Phase 3.7**, which runs per-card BEFORE the Phase 4 commit. The post-batch `/codexreview` in the Final review remains as a final FULL-diff sweep over the entire batch (since v3.37.0 — the guaranteed full-depth merge gate). This Phase 3 focuses exclusively on documentation sync, which must happen per-card (tied to the specific commit).
1226
1295
 
1296
+ > **Deferral gate (since v4.7.0 — enumerated, `review_profile`-driven)**: SKIP per-card doc-review and defer it to the **Final Review F.3 doc-reviewer** (which runs over the entire batch) when the card is **`review_profile == light` AND its committed diff touches NO documentation file** (no `.md`, no path under `${paths.references_dir}`, no data-model/ssot/api doc). These are small code changes with no doc surface of their own; their only doc concern is drift, which the batch-wide Final doc-reviewer catches. Log `doc-review: DEFERRED to Final FULL gate (light, no doc files in diff)` and proceed to Phase 3.5. **KEEP per-card doc-review** for: `balanced`/`deep` cards, ANY card whose diff touches a doc file (the change IS doc-relevant), and trivial cards (doc-review is their primary gate — § "Trivial-card fast-lane", unchanged). Never defer "for time" — the only enumerated reason is `light + non-doc diff`.
1297
+
1227
1298
  12. **Update tracker**: phase = "3-doc-review".
1228
1299
  13. Build a **Doc Sync Context** block. The coder committed in Phase 2, so detect the card's changed files against the trunk (a bare `HEAD` diff would be empty post-commit):
1229
1300
  ```bash
@@ -1289,7 +1360,8 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1289
1360
  19. **Select QA profile**: READ the card's `review_profile` field (use verbatim); only compute via the QA Profile Selector above (whose criteria SSOT is `prd-card-writer.md § Rule C`) when the field is absent (legacy card). Log the chosen profile and its source (`from card` | `computed`) in the tracker (1 line).
1290
1361
  20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
1291
1362
  21. **If profile is LIGHT**: SKIP qa-sentinel. Phase 2 step 8 ran lint/tsc/test/build, AND the two code-mutating phases that follow it (Phase 2.55 Simplify, Phase 3 doc-reviewer) each re-run lint + tsc on their post-mutation output (so the static checks cover the committed code, not just the pre-mutation code). Log "QA LIGHT skipped — lint/tsc/test/build passed in Phase 2 and lint/tsc re-ran post-mutation in 2.55/3" in the tracker. Proceed to Phase 4.
1292
- 22. **If profile is BALANCED or DEEP**: invoke the **`qa-sentinel`** agent (subagent_type: `qa-sentinel`) via Task tool with the following context:
1363
+ 21b. **If profile is BALANCED (since v4.7.0 — deferral to Final, enumerated `review_profile`-driven)**: SKIP per-card qa-sentinel and **defer the test suite to the Final Review F.3 qa-sentinel** (which runs the FULL suite + build + audit over the entire batch — the unconditional merge gate). Phase 2 step 8 already ran lint/tsc/test/build on this card's diff. **Exception — risk escalation runs FULL per-card anyway**: if the Phase 3.7 Step A detector matched any high-risk trigger on this card's diff (auth/permission/payment/schema/migration/API-contract), do NOT defer — run qa-sentinel at FULL here for fail-fast. Log `QA balanced deferred to Final FULL gate (no risk escalation)` or `QA balanced escalated to FULL (risk drift: <trigger>)`. ⚠️ Most `feature`/`enhancement` cards are `balanced` (Rule C), so a balanced-only batch first runs the suite at the Final gate; the merge gate stays safe (Final = full suite over the whole batch). Proceed to Phase 4 when deferred.
1364
+ 22. **If profile is DEEP (or BALANCED escalated by risk drift — see 21b)**: invoke the **`qa-sentinel`** agent (subagent_type: `qa-sentinel`) via Task tool with the following context:
1293
1365
 
1294
1366
  ```
1295
1367
  Run QA gates on card <CARD-ID> at the tier dictated by the QA profile below (do NOT default to FULL).
@@ -1301,11 +1373,12 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1301
1373
  - Worktree path: <worktree-path> — `cd` into it before running any gate
1302
1374
  - Branch: <branch-name>
1303
1375
  - Changed files: <list from implementation phase>
1304
- - QA profile: [balanced | deep]
1376
+ - QA profile: [deep | balanced-escalated]
1305
1377
 
1306
- Tier contract: balancedSCOPED (related tests on touched modules); deep FULL suite.
1307
- Only path-based risk drift (auth/permission/payment/schema/migration/API contract in the diff)
1308
- may escalate balanced→FULL. File count never escalates.
1378
+ Tier contract: deepFULL suite. A BALANCED card only reaches this step when risk drift
1379
+ escalated it (step 21b) — run it at FULL too (the escalation reason is the fail-fast signal).
1380
+ A non-escalated balanced card never reaches here (its suite is deferred to the Final FULL gate
1381
+ per step 21b). File count never escalates.
1309
1382
 
1310
1383
  E2E is NOT your job (run by the /e2e-review skill in Phase 2.6) — do NOT run Playwright.
1311
1384
  Run the gates: lint, tsc (when stack.language includes typescript), test (per tier), build, markdownlint.
@@ -1328,7 +1401,9 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1328
1401
 
1329
1402
  ### Phase 3.7 — Pre-Merge Codex Review Gate (MANDATORY — UNCONDITIONAL)
1330
1403
 
1331
- **This gate is NON-SKIPPABLE and runs for EVERY card before the Phase 4 commit, no matter what.** A per-card `/codexreview` MUST run BEFORE the Phase 4 commit, regardless of file paths, card type, or perceived risk. The historical conditional High-Risk Path detector is preserved below — but only as a **signal-logging step** to record *which* triggers matched in the tracker. It NEVER suppresses the `/codexreview` invocation. Even if zero triggers match, `/codexreview` runs.
1404
+ **This gate runs for EVERY card with code to review before the Phase 4 commit.** A per-card `/codexreview` MUST run BEFORE the Phase 4 commit, regardless of file paths or perceived risk. The historical conditional High-Risk Path detector is preserved below — but only as a **signal-logging step** to record *which* triggers matched in the tracker. It NEVER suppresses the `/codexreview` invocation. Even if zero triggers match, `/codexreview` runs.
1405
+
1406
+ > **Single carve-out — `IS_TRIVIAL` fast-lane (since v4.6.0)**: a card that is `IS_TRIVIAL` on its ACTUAL committed diff (`review_profile=skip` + non-source diff + 0 Step-A triggers — § "Trivial-card fast-lane") **skips this gate**, because there is no code for Codex to review. Its adversarial coverage is carried by the SAME unconditional **Final-review FULL gate** the `light` path already relies on (it runs Codex over the entire batch diff, including every trivial card's files, before merge). This is NOT a `time budget` skip — it is the deterministic `IS_TRIVIAL` gate reason, and the guard means a single source file in the diff flips the card back onto this gate. Log `codex-review: SKIPPED (trivial — non-source diff; covered by Final FULL gate)`.
1332
1407
 
1333
1408
  **Rationale**: leaving the gate conditional caused it to be silently skipped on the majority of cards, defeating the AGENTS.md "MUST run BEFORE merge" requirement. The gate itself is unconditional — what varies is its DEPTH (`light` vs `full`). The protection against a missed blocker on a "low-risk" path (BUG-0530-class regressions) is carried by two mechanisms, not by an always-on per-card Codex pass: (1) the Step A detector escalates any risky diff to `full` per-card, and (2) the unconditional **Final-review FULL gate** runs Codex adversarial over the entire batch diff before merge. So `light` can safely run `code-reviewer` + FP-gate only (since v3.38.0) without weakening the merge gate.
1334
1409
 
@@ -1437,10 +1512,15 @@ For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH var
1437
1512
  Write `/tmp/codexreview-lean-<CARD-ID>.json`:
1438
1513
  ```json
1439
1514
  { "profile": "light|full", "arch_baseline_path": "/tmp/arch-baseline-<CARD-ID>.md",
1440
- "diff_summary_path": "/tmp/diff-<CARD-ID>.txt", "skip_doc_reviewer": true }
1515
+ "diff_summary_path": "/tmp/diff-<CARD-ID>.txt", "skip_doc_reviewer": true,
1516
+ "skip_api_perf_auditor": true }
1441
1517
  ```
1442
1518
  `skip_doc_reviewer` is ALWAYS true: Phase 3 already ran `doc-reviewer` on this diff (with the
1443
- spec/docs-drift→bug lens since v3.35.0), so `/codexreview` agent #4 would be a duplicate.
1519
+ spec/docs-drift→bug lens since v3.35.0), so `/codexreview` agent #3 would be a duplicate.
1520
+ `skip_api_perf_auditor` is ALWAYS true (since v4.7.0): the per-card api-perf/cost pass is deferred
1521
+ to the **Final Review F.3 api-perf-cost-auditor** (batch-wide), so `/codexreview` agent #2 would be
1522
+ a duplicate of the final sweep. (At `full` `/codexreview` would otherwise spawn it; at `light` it is
1523
+ already dropped.)
1444
1524
 
1445
1525
  1. **Log gate invocation** in the tracker under `## Pre-Merge Codex Review`:
1446
1526
 
@@ -2385,11 +2465,13 @@ After ALL agents in the group complete successfully:
2385
2465
  - **Partition** the group into two lists and log them in the tracker under `## Team Mode`:
2386
2466
  - `LIGHT_CARDS` = cards whose effective profile is `light` or `skip` **AND** zero Step-A triggers.
2387
2467
  - `FULL_CARDS` = all others (effective profile `balanced`/`deep`, OR any Step-A trigger).
2388
- - Log: `## D.1.5 Effective Profiles\n<CARD-ID>: profile=<floor> triggers=<n> effective=<light|full> (<LIGHT_CARDS|FULL_CARDS>)` per card. This single computation is the SSOT for both D.2 (code-reviewer scoping) and D.4b (inclusion) do NOT recompute it in either step.
2468
+ - **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.)
2469
+ - **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.)
2470
+ - 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.
2389
2471
 
2390
2472
  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):
2391
- - **doc-reviewer — over the WHOLE group, always** (unchanged). 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). D.4a consumes these per-card findings 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.
2392
- - **code-reviewer — scoped to the diff-union of `LIGHT_CARDS` ONLY** (run it in parallel with the doc-reviewer over those files). `LIGHT_CARDS` cards skip D.4b, so D.2 is their single per-card code review (the cross-batch Codex pass at Final covers them adversarially). **If `LIGHT_CARDS` is empty → do NOT spawn code-reviewer at D.2** (every card is `FULL_CARDS` and receives its deeper code review — `code-reviewer` + Codex + CoVe + FP — at D.4b). Log the deterministic gate reason: `D.2 code-reviewer: scope=LIGHT_CARDS [<ids>] | SKIPPED (no light cards — code-review owned by D.4b per-card + Final FULL gate)`.
2473
+ - **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.
2474
+ - **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.4bor `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)`.
2393
2475
  - **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`.
2394
2476
 
2395
2477
  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.
@@ -2403,14 +2485,14 @@ After ALL agents in the group complete successfully:
2403
2485
  - **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.
2404
2486
  - 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.
2405
2487
 
2406
- 4. **D.4 — QA gate (group)** — Read each card's `review_profile` field (fallback for legacy cards only: compute via the QA Profile Selector, whose criteria are the SSOT in `prd-card-writer.md § Rule C`). Select the HIGHEST profile across all cards in the group (e.g., if one card is BALANCED and another is DEEP, use DEEP) and pass it as the `QA profile` to **qa-sentinel** (invoked once for the group) using the same prompt contract as Phase 3.5 step 22 (`do NOT default to FULL`; balanced SCOPED, deep FULL). Note: a mixed group containing any DEEP card runs the group at FULL the max-profile intentionally overrides the SCOPED tier the BALANCED cards would get individually, because the combined diff must be validated together.
2488
+ 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.
2407
2489
 
2408
2490
  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.
2409
2491
 
2410
2492
  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.
2411
2493
  - **`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)`.
2412
2494
  - **`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).
2413
- 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`, 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.
2495
+ 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.
2414
2496
 
2415
2497
  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):
2416
2498
  ```bash
@@ -2437,14 +2519,16 @@ After ALL agents in the group complete successfully:
2437
2519
 
2438
2520
  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):
2439
2521
 
2440
- - `## AC Closure Ledger — <CARD-ID>` with `ac-closure: implemented=N | user-approved deferrals=M | follow-up cards created=K`
2522
+ - `## 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)
2441
2523
  - `simplify: <N fixes | clean — 0 fixes | SKIPPED (review_profile=skip)>` (per-card from D.3b)
2442
2524
  - `e2e-review: <status>` (with documented gate-skip reason if SKIP)
2443
- - `doc-review: <status>` (from D.4a)
2444
- - `qa: <profile=... | verdict=...>` (group-level from D.4 same value cited per card)
2445
- - `codex-review: <verdict | SKIPPED (light, 0 triggers — D.2 group code-review covered + Final FULL gate)>` (per-card from D.4b the SKIPPED form is valid ONLY for cards in `LIGHT_CARDS` per the D.1.5 partition)
2525
+ - `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)
2526
+ - `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)
2527
+ - `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)
2528
+ - `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)
2529
+ - `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)
2446
2530
 
2447
- A missing entry means a sub-step was skipped. An entry whose value is a **`review_profile`-driven SKIP** with the documented enumerated reason above (D.3b `skip` profile, D.4b `LIGHT_CARDS`) is a VALID, present entry — not a violation. 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.
2531
+ 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.
2448
2532
 
2449
2533
  #### Step E: Context purge + next group
2450
2534
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.5.0",
3
+ "version": "4.7.0",
4
4
  "description": "Claude Agent Framework - Reusable framework for coordinating AI agents and humans in software projects",
5
5
  "bin": {
6
6
  "baldart": "./bin/baldart.js"