baldart 4.6.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,17 @@ 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
+
8
19
  ## [4.6.0] - 2026-06-03
9
20
 
10
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).
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.6.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`, **the card's `review_profile`-driven review depth — see next paragraph — and the `IS_TRIVIAL` fast-lane (`review_profile=skip` + non-source diff + 0 high-risk triggers), defined once in § "Trivial-card fast-lane"**). 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
 
@@ -497,7 +497,16 @@ For each card, execute these phases in order:
497
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
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.)
499
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.
500
- 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):
501
510
  ```
502
511
  mode: QUICK
503
512
  Grounding check only (NOT a full audit — do not run the full AUDIT CHECKLIST A-H, and do not
@@ -1284,6 +1293,8 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1284
1293
 
1285
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).
1286
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
+
1287
1298
  12. **Update tracker**: phase = "3-doc-review".
1288
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):
1289
1300
  ```bash
@@ -1349,7 +1360,8 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1349
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).
1350
1361
  20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
1351
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.
1352
- 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:
1353
1365
 
1354
1366
  ```
1355
1367
  Run QA gates on card <CARD-ID> at the tier dictated by the QA profile below (do NOT default to FULL).
@@ -1361,11 +1373,12 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1361
1373
  - Worktree path: <worktree-path> — `cd` into it before running any gate
1362
1374
  - Branch: <branch-name>
1363
1375
  - Changed files: <list from implementation phase>
1364
- - QA profile: [balanced | deep]
1376
+ - QA profile: [deep | balanced-escalated]
1365
1377
 
1366
- Tier contract: balancedSCOPED (related tests on touched modules); deep FULL suite.
1367
- Only path-based risk drift (auth/permission/payment/schema/migration/API contract in the diff)
1368
- 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.
1369
1382
 
1370
1383
  E2E is NOT your job (run by the /e2e-review skill in Phase 2.6) — do NOT run Playwright.
1371
1384
  Run the gates: lint, tsc (when stack.language includes typescript), test (per tier), build, markdownlint.
@@ -1499,10 +1512,15 @@ For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH var
1499
1512
  Write `/tmp/codexreview-lean-<CARD-ID>.json`:
1500
1513
  ```json
1501
1514
  { "profile": "light|full", "arch_baseline_path": "/tmp/arch-baseline-<CARD-ID>.md",
1502
- "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 }
1503
1517
  ```
1504
1518
  `skip_doc_reviewer` is ALWAYS true: Phase 3 already ran `doc-reviewer` on this diff (with the
1505
- 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.)
1506
1524
 
1507
1525
  1. **Log gate invocation** in the tracker under `## Pre-Merge Codex Review`:
1508
1526
 
@@ -2448,10 +2466,11 @@ After ALL agents in the group complete successfully:
2448
2466
  - `LIGHT_CARDS` = cards whose effective profile is `light` or `skip` **AND** zero Step-A triggers.
2449
2467
  - `FULL_CARDS` = all others (effective profile `balanced`/`deep`, OR any Step-A trigger).
2450
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.)
2451
- - 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 if applicable>` per card. This single computation is the SSOT for D.2 (code-reviewer scoping), D.3b/D.3c (already skipped for trivial), and D.4b (inclusion)do NOT recompute it downstream.
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.
2452
2471
 
2453
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):
2454
- - **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.
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.
2455
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.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)`.
2456
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`.
2457
2476
 
@@ -2466,14 +2485,14 @@ After ALL agents in the group complete successfully:
2466
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.
2467
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.
2468
2487
 
2469
- 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.
2470
2489
 
2471
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.
2472
2491
 
2473
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.
2474
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)`.
2475
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).
2476
- 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.
2477
2496
 
2478
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):
2479
2498
  ```bash
@@ -2503,12 +2522,13 @@ Before moving to Step E, the orchestrator MUST verify the tracker contains, for
2503
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)
2504
2523
  - `simplify: <N fixes | clean — 0 fixes | SKIPPED (review_profile=skip)>` (per-card from D.3b)
2505
2524
  - `e2e-review: <status>` (with documented gate-skip reason if SKIP)
2506
- - `doc-review: <status>` (from D.4a — runs for trivial cards too)
2507
- - `qa: <profile=... | verdict=... | mechanical-only (trivial)>` (group-level from D.4; for a `TRIVIAL_CARDS`-only ride-along the trivial card cites the group value or `mechanical-only`)
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)
2508
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)
2509
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)
2510
2530
 
2511
- A missing entry means a sub-step was skipped. An entry whose value is a **`review_profile`-driven SKIP** or **`IS_TRIVIAL` SKIP** with the documented enumerated reason above (D.3b `skip` profile, D.4b `LIGHT_CARDS`, code/codex `TRIVIAL_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.
2512
2532
 
2513
2533
  #### Step E: Context purge + next group
2514
2534
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.6.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"