baldart 3.37.0 → 3.39.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,71 @@ 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
+ ## [3.39.0] - 2026-06-01
9
+
10
+ **A `/prd` or `/new` run now CONCLUDES clean — it never ends by handing the user a list of "azioni tue, non bloccanti" (an uncommitted file blocking the local `develop` fast-forward, a merged remote branch left undeleted).** Every workspace-hygiene leftover is either auto-resolved by the finalizer or put behind ONE explicit `AskUserQuestion` gate. No passive manual TODO ever survives into the final summary. **No new `baldart.config.yml` keys.**
11
+
12
+ > **Why.** A `/prd` finalization closed with: *"il develop locale non si è fast-forwardato per una modifica non committata pre-esistente a `docs/metrics/skill-runs.jsonl` — gestisci quel file e poi `git pull --ff-only`"* and *"il branch remoto non è stato eliminato — puoi cancellarlo a mano"*. The orchestrator declared the run "completato" while leaving the workspace half-finished. Root cause: `worktree-manager mw-docs` printed `⚠️ … Leaving as-is` on a blocked fast-forward, and `/prd` (unlike `/new` Phase 6c) had no workspace-hygiene phase to consume that — it forwarded the warning to the user verbatim.
13
+
14
+ ### Changed — the merge finalizer auto-resolves instead of giving up
15
+
16
+ - **[framework/.claude/skills/worktree-manager/SKILL.md](framework/.claude/skills/worktree-manager/SKILL.md)** (Common — sync local develop): the blocked-ff path no longer prints `Leaving as-is`. It partitions the dirty tree: the framework-owned append-only telemetry log (`docs/metrics/skill-runs.jsonl`) is reconciled autonomously and losslessly (commit + `pull --rebase` + best-effort push) so the ff completes; ANY foreign file emits a new `[SYNC-NEEDS-DECISION]` marker the orchestrator MUST convert into one explicit gate. Work this run does not own is never auto-committed.
17
+ - **[framework/.claude/skills/worktree-manager/SKILL.md](framework/.claude/skills/worktree-manager/SKILL.md)** (Cleanup step 6.3 + report): merged remote-branch deletion is now an explicit, reported step (was `2>/dev/null || true` silent) — a denial is retried, never degraded into a "puoi cancellarlo a mano" note.
18
+
19
+ ### Added — `/prd` Step 7.5 Workspace Hygiene & finalization (BLOCKING)
20
+
21
+ - **[framework/.claude/skills/prd/references/validation-phase.md](framework/.claude/skills/prd/references/validation-phase.md)**: new Step 7.5 mirrors `/new` Phase 6c — consumes the `[SYNC-NEEDS-DECISION]` / `[SYNC-DEFERRED]` markers, raises ONE `AskUserQuestion` per unresolved residue, ensures the merged remote branch is gone. New **HARD RULE** in Final output: the summary MUST NOT contain a "azioni tue / note non bloccanti" section — a run that prints "gestisci tu il file e poi pulla" has FAILED Step 7.5.
22
+
23
+ ### Changed — `/new` Phase 6c parses the new marker
24
+
25
+ - **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)** (Phase 6c step 2): now also parses `[SYNC-NEEDS-DECISION]` (foreign-file ff block / rebase conflict) as a blocking gate, alongside the existing `[SYNC-DEFERRED]`.
26
+
27
+ ### Changed — AGENTS.md scopes branch-deletion approval to unmerged branches
28
+
29
+ - **[framework/AGENTS.md](framework/AGENTS.md)**: owner approval is required before deleting an **unmerged** branch; deleting an **already-merged** feature branch is routine cleanup the merge skill performs automatically (no separate approval). The "prune remote branches only when instructed" rule is clarified to exclude a feature branch's own ref on successful merge.
30
+
31
+ ### Revert
32
+
33
+ - Restore the `git -C "$MAIN" pull --ff-only origin develop || echo "⚠️ … Leaving as-is."` one-liner in `worktree-manager` and drop `/prd` Step 7.5.
34
+
35
+ ## [3.38.0] - 2026-06-01
36
+
37
+ **The per-card review depth (QA + Codex) is now decided deterministically in the backlog card via a new `review_profile` field, computed once at PRD authoring time — instead of being re-derived heuristically by `/new` at runtime.** This removes the implementing agent's interpretation latitude: the card carries `skip|light|balanced|deep`, `/new` READS it, and only falls back to runtime computation for legacy cards that predate the field. **No new `baldart.config.yml` keys** — this is a backlog-card schema change, propagated end-to-end across templates + card-writer + validation + `/new` in the same release.
38
+
39
+ > **Why.** Previously the QA Profile Selector (Phase 3.5) and the Codex Review Profile Selector (Phase 3.7) both recomputed the profile inside `/new` from soft signals (title keywords, the self-admittedly-unreliable `files_likely_touched`), so the same card could be reviewed differently depending on the orchestrator's reading. The card already encodes every hard signal needed (`owner_agent`, type, `areas`, `data_fields`, `db_indexes`, `acceptance_criteria`, `estimated_complexity`) — so the decision is now made once, in the card, by the deterministic rules in `prd-card-writer.md § Rule C` (the SSOT).
40
+
41
+ ### Added — `review_profile` card field (deterministic review depth)
42
+
43
+ - **[framework/.claude/skills/prd/assets/card-template.yml](framework/.claude/skills/prd/assets/card-template.yml)** + **[framework/templates/feature-card.template.yml](framework/templates/feature-card.template.yml)** + **[framework/.claude/skills/prd/assets/epic-template.yml](framework/.claude/skills/prd/assets/epic-template.yml)**: new `review_profile: skip|light|balanced|deep` field. Epics are always `skip` (trackers, no code work). Authors MAY override the computed value by hand.
44
+ - **[framework/.claude/agents/prd-card-writer.md](framework/.claude/agents/prd-card-writer.md)**: new **Rule C** — the canonical mapping table (metadata → profile) and the SSOT for the decision. Added `review_profile` to the required-fields list. `feature`/`enhancement` cards are floored at `balanced` (never `light`).
45
+ - **[framework/.claude/skills/prd/references/validation-phase.md](framework/.claude/skills/prd/references/validation-phase.md)**: Step 6.0 now BLOCKS on a missing/out-of-enum `review_profile` (mirrors the `owner_agent` gate), with a soft WARN+normalize for `feature`-card-`light` violations and epic non-`skip` values.
46
+ - **[framework/.claude/skills/prd/references/backlog-phase.md](framework/.claude/skills/prd/references/backlog-phase.md)**: documents that `prd-card-writer` populates `review_profile`.
47
+
48
+ ### Changed — `/new` reads the field instead of recomputing it
49
+
50
+ - **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)** (QA Profile Selector): primary path now READS `review_profile` from the card verbatim; the existing rule table is demoted to a **legacy-card fallback** with an explicit "keep in sync with `prd-card-writer.md § Rule C` (SSOT)" note.
51
+ - **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)** (Phase 3.7 Step C.0): the Codex profile derives from the card's `review_profile` (`skip`/`light` → Codex `light`, `balanced`/`deep` → Codex `full`). New **escalation-only invariant**: the Step A high-risk diff detector can only promote `light` → `full` (a risk surfaced at implementation time the authored profile didn't anticipate), never downgrade `full` → `light`. The card's `review_profile` is the deterministic floor; the diff detector is the safety net on top.
52
+ - **[framework/.claude/commands/new.md](framework/.claude/commands/new.md)**: thin mirror updated to the read-from-card primary path with compute-fallback.
53
+
54
+ ### Changed — `light` profile no longer runs the per-card Codex adversarial pass
55
+
56
+ - **[framework/.claude/commands/codexreview.md](framework/.claude/commands/codexreview.md)** (Step -0.5) + **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)** (Phase 3.7 Step C.0, Team D.4b): at `profile: light`, `/codexreview` now omits agent #5 (Codex adversarial) in addition to qa-sentinel + api-perf-cost-auditor + Step 3.5 CoVe. **`light` per-card = `code-reviewer` + the false-positive gate only.** The Codex adversarial review becomes the prerogative of `full` and of the final cross-check.
57
+ - **Why it's safe (BUG-0530 invariant relocated, not dropped)**: the "never miss a blocker on a low-risk path" guarantee is now carried by (1) the **escalation-only** Step A detector — any high-risk path in the actual diff promotes `light` → `full`, so risky code still gets per-card Codex adversarial immediately; and (2) the unconditional **Final-review FULL gate** (v3.37.0), which runs Codex adversarial over the entire batch diff before merge. So every `light` card's code is still Codex-reviewed at least once pre-merge — the pass is paid once at the batch gate instead of N times per-card. Trade-off: a Codex-class finding on a 0-trigger `light` card surfaces at the final gate rather than per-card (later fix-cycle, still pre-merge).
58
+ - **Revert**: re-add agent #5 to the `light` branch of `/codexreview` Step -0.5.
59
+
60
+ ### Backward compatibility
61
+
62
+ - **Non-breaking**: backlogs authored before v3.38.0 have no `review_profile`. `/new` silently falls back to the runtime rule table (logging `computed — review_profile absent`), so existing cards run exactly as before. New PRD-generated cards get the field automatically.
63
+
64
+ ## [3.37.1] - 2026-06-01
65
+
66
+ **`/prd` Step 7 merge is fully seamless — auto merge + worktree cleanup with zero end-of-session questions; the user is asked ONLY for conflicts `mw-docs` genuinely cannot auto-resolve.** Fixes a drift between the `/prd` `validation-phase.md` and the real `worktree-manager mw-docs` behaviour that made the skill over-ask. No new `baldart.config.yml` keys.
67
+
68
+ ### Fixed — `/prd` no longer over-asks at merge time
69
+
70
+ - **[framework/.claude/skills/prd/references/validation-phase.md](framework/.claude/skills/prd/references/validation-phase.md)**: the cross-PRD-collision note and the Step 7 conflict-resolution table claimed structured registries (`project-status.md`, `ssot-registry.md`, …) "abort the rebase and ask for manual resolution". That contradicted `worktree-manager` `mw-docs`, which actually strips markers + runs a structural validation and only aborts when the validation fails (the rare same-row collision). Aligned both spots to the real behaviour: append-only registries auto-resolve and merge with zero questions; escalation happens **only** on a genuinely unresolvable conflict (code/test/fixture, or a structured registry whose strip+validate failed).
71
+ - **[framework/.claude/skills/prd/references/validation-phase.md](framework/.claude/skills/prd/references/validation-phase.md)** (Step 7 step 9): reinforced "no confirmation prompt" — explicitly forbids the "vuoi che mergi e pulisca il worktree?" pre-emptive gate. Merge **and** cleanup run automatically; the model lets `mw-docs` run and only surfaces what it actually reports as unresolvable, instead of asking "just in case".
72
+
8
73
  ## [3.37.0] - 2026-05-30
9
74
 
10
75
  **Two-tier review for `/new`: fast `light` per-card during the loop, one guaranteed FULL pass over the whole batch before merge.** This activates the dormant v3.35.0 Review Profile Selector AND re-introduces an unconditional final full review — together they cut tokens/wall-clock on low-risk cards *without* weakening the merge gate. **No new `baldart.config.yml` keys** — both are changes inside the skill, so the schema-propagation rule does not apply.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.37.0
1
+ 3.39.0
@@ -155,6 +155,40 @@ files and one file would be torn between two cards), prefer a single
155
155
  assign `ui-expert` to a mixed card. The dispatcher's specialist routing
156
156
  breaks down when scope is mixed.
157
157
 
158
+ ### Rule C — Compute `review_profile` on every child card (SSOT — deterministic)
159
+
160
+ Every child card MUST set `review_profile` to exactly one of:
161
+
162
+ ```
163
+ skip | light | balanced | deep
164
+ ```
165
+
166
+ This field materializes the per-card review DEPTH **at authoring time**, so the
167
+ `/new` orchestrator READS it instead of re-deriving it heuristically at runtime.
168
+ The single field drives BOTH the QA depth (`/new` Phase 3.5) and the Codex review
169
+ profile (`/new` Phase 3.7 — `skip`/`light` → Codex `light`, `balanced`/`deep` →
170
+ Codex `full`). **This table is the Single Source of Truth**; the fallback table in
171
+ `framework/.claude/skills/new/SKILL.md § QA Profile Selector` exists only for legacy
172
+ cards that predate this field and MUST stay in sync with the rules below.
173
+
174
+ Apply the **first matching rule** (priority order — top wins):
175
+
176
+ | Profile | When to assign |
177
+ |---------|----------------|
178
+ | **DEEP** | ANY of: `areas` includes both `api` AND `data` — OR title/scope/areas touch `auth`, `payment`, `permission`, `schema`, `migration`, `cron`, `webhook`, `transaction` — OR `data_fields` has ≥3 entries with `status: new` or `status: modified` — OR `db_indexes` present (legacy `firestore_indexes` too) — OR acceptance criteria count > 5 — OR `estimated_complexity: HIGH` — OR API contract changed |
179
+ | **LIGHT** | Card is a `bugfix` or `refactor` — AND ≤3 files in `files_likely_touched` — AND none of the DEEP high-risk keywords/areas apply. **NEVER for `feature` or `enhancement` cards.** |
180
+ | **SKIP** | Card is `docs`, `chore`, or `config` — OR all `files_likely_touched` are `.md`/non-API `.yml`/CSS with zero logic files — OR a pure-cosmetic card (typo/rename/copy/wording/style) with no code areas |
181
+ | **BALANCED** | Default for everything else — ALL `feature`/`enhancement` cards not matching DEEP, plus any `bugfix`/`refactor` with >3 files or breadth that isn't DEEP |
182
+
183
+ **Critical**: `feature` and `enhancement` cards are ALWAYS `balanced` minimum — never
184
+ `light`. When in doubt between `balanced` and `deep`, choose `deep`. `files_likely_touched`
185
+ counts are advisory only — never downgrade a feature card below `balanced` because the
186
+ file count looks small. **Epic cards** always use `review_profile: skip` (no code work).
187
+
188
+ The human author MAY override the computed value by editing the card YAML — e.g. to
189
+ force `deep` on a card they consider sensitive. Honor any explicit value already present;
190
+ only compute when the field is empty.
191
+
158
192
  ## Card Atomicity Rules
159
193
 
160
194
  Cards MUST be as atomic as possible to enable parallel execution:
@@ -284,6 +318,7 @@ Every card MUST include ALL fields from the template:
284
318
  - `definition_of_done` (checklist including doc invariants)
285
319
  - `depends_on` / `blocks` (card IDs)
286
320
  - `estimated_complexity`
321
+ - `review_profile` (`skip`|`light`|`balanced`|`deep` — computed via Rule C, or honored if pre-set)
287
322
  - `files_likely_touched` (exact paths with NEW/MODIFY)
288
323
  - `links.prd` (path to PRD)
289
324
  - `links.design` (path to design.html — REQUIRED for any card with UI scope)
@@ -55,17 +55,21 @@ For the (single) card in scope, check for `/tmp/codexreview-lean-<CARD-ID>.json`
55
55
  - `skip_doc_reviewer: true` → **omit agent #4 (`doc-reviewer`)** in Step 2. Doc concerns are covered
56
56
  by `/new` Phase 3, which runs `doc-reviewer` (with the spec/docs-drift lens) on the same diff
57
57
  immediately before this gate. *(A2)*
58
- - `profile: "light"` → ALSO omit agent #2 (`qa-sentinel`) and agent #3 (`api-perf-cost-auditor`),
59
- and **skip Step 3.5 (CoVe)**. Agent #1 (`code-reviewer`), agent #5 (**Codex adversarial**), and
60
- the Step 3 false-positive gate ALWAYS run. *(B1)*
61
- - `profile: "full"` (or missing) full agent set, minus #4 if `skip_doc_reviewer`.
62
-
63
- **Invariant**: lean mode NEVER suppresses the run itself at minimum `code-reviewer` + Codex
64
- adversarial + Step 3 FP-gate execute on every card. If the contract file is malformed/unreadable,
65
- fall back to **full mode** and note it. **Consume-once**: delete `/tmp/codexreview-lean-<CARD-ID>.json`
58
+ - `profile: "light"` → ALSO omit agent #2 (`qa-sentinel`), agent #3 (`api-perf-cost-auditor`),
59
+ **agent #5 (Codex adversarial)** (since v3.38.0), and **skip Step 3.5 (CoVe)**. Only agent #1
60
+ (`code-reviewer`) and the Step 3 false-positive gate run. The Codex adversarial pass is the
61
+ prerogative of `full` and of the final cross-check every `light` card's code is still reviewed
62
+ by Codex adversarial at the unconditional Final-review FULL gate before merge (see `/new`
63
+ "Final-review FULL gate"), and any high-risk diff trigger escalates the card to `full` per-card
64
+ so it gets Codex adversarial immediately. *(B1)*
65
+ - `profile: "full"` (or missing) → full agent set incl. Codex adversarial, minus #4 if `skip_doc_reviewer`.
66
+
67
+ **Invariant**: lean mode NEVER suppresses the run itself — at minimum `code-reviewer` + the Step 3
68
+ FP-gate execute on every card (`light`); `full` additionally runs the Codex adversarial pass. If the
69
+ contract file is malformed/unreadable, fall back to **full mode** and note it. **Consume-once**: delete `/tmp/codexreview-lean-<CARD-ID>.json`
66
70
  immediately after parsing it, so a later standalone `/codexreview <CARD-ID>` on the same card never
67
71
  inherits a stale lean contract from a prior `/new` run. Record the resolved mode in the Step 4 report
68
- `Method` section, e.g. `lean: profile=light, architect=reused, doc-reviewer=skipped(Phase 3), cove=skipped`.
72
+ `Method` section, e.g. `lean: profile=light, architect=reused, doc-reviewer=skipped(Phase 3), codex=skipped(light), cove=skipped`.
69
73
 
70
74
  ---
71
75
 
@@ -144,8 +148,10 @@ Launch these agents in parallel for each card:
144
148
  5. **Codex (GPT-5.5)** — adversarial review via `codex-companion.mjs`
145
149
 
146
150
  > **Lean agent set (Step -0.5)**: when a contract file is active, launch only the agents the resolved
147
- > mode permits — `skip_doc_reviewer` omits #4; `profile: light` additionally omits #2 and #3. Agents
148
- > #1 (`code-reviewer`) and #5 (Codex) ALWAYS launch. In full mode (no contract file), launch all five.
151
+ > mode permits — `skip_doc_reviewer` omits #4; `profile: light` additionally omits #2, #3, AND **#5
152
+ > (Codex adversarial)** (since v3.38.0). At `light`, only agent #1 (`code-reviewer`) launches (+ the
153
+ > Step 3 FP-gate). At `full` (and in full mode with no contract file), launch all five (Codex #5
154
+ > included). The standalone `/codexreview <CARD-ID>` invocation (no contract) is always full.
149
155
 
150
156
  **Codex invocation rules (agent #5):**
151
157
 
@@ -238,7 +244,7 @@ Write one consolidated report per run to `/tmp/codexreview-report-<TIMESTAMP>.md
238
244
  Report structure:
239
245
 
240
246
  1. `Scope Reviewed`
241
- 2. `Method` (agents used + validation flow; note whether Codex was available or `CODEX_UNAVAILABLE`; note whether Step 3.5 CoVe ran fully or hit budget cap; in lean mode, record the resolved contract — `lean: profile=<light|full>, architect=<reused|spawned>, doc-reviewer=<skipped(Phase 3)|run>, cove=<skipped|run>`)
247
+ 2. `Method` (agents used + validation flow; note whether Codex was available or `CODEX_UNAVAILABLE`; note whether Step 3.5 CoVe ran fully or hit budget cap; in lean mode, record the resolved contract — `lean: profile=<light|full>, architect=<reused|spawned>, doc-reviewer=<skipped(Phase 3)|run>, codex=<skipped(light)|run>, cove=<skipped|run>`)
242
248
  3. `Verified Bugs` (ordered: BLOCKER -> HIGH -> MEDIUM -> LOW; tag findings with `[codex]` if originating from Codex; tag `[ripple-expanded]` if Step 3.5 added `ripple_files`; tag `[cove_unverified]` if Step 3.5 budget exhausted before reaching it)
243
249
  4. `Needs Manual Confirmation`
244
250
  5. `False Positives Discarded` (with reason)
@@ -98,9 +98,9 @@ Main repo: [/absolute/path/to/main/repo]
98
98
 
99
99
  ## QA Profile Selector
100
100
 
101
- Before Phase 3.5, determine the QA profile for each card by reading its YAML metadata. Use the **first matching rule** (priority order):
101
+ Before Phase 3.5, determine the review profile for each card. **Primary path (since v3.38.0): READ the card's `review_profile` field** (`skip|light|balanced|deep`), computed deterministically by the PRD `prd-card-writer` (SSOT). Use it verbatim — do NOT recompute. **Fallback (legacy cards with no field): compute** from the table below (the SKILL.md version is authoritative — keep in sync with `prd-card-writer.md § Rule C`).
102
102
 
103
- | Profile | When to apply |
103
+ | Profile | When to apply (fallback compute only) |
104
104
  |---------|--------------|
105
105
  | **SKIP** | Card type is `docs`, `chore`, or `config` — OR all changed paths are `.md`/`.yml` (non-API)/CSS with zero logic files — OR title contains only cosmetic keywords (typo, rename, copy, wording, style) with no code areas |
106
106
  | **LIGHT** | 5 or fewer files likely touched — AND no HIGH-risk keywords in paths/areas — OR card type is `bugfix` with small scope — OR pure refactoring with no logic change |
@@ -141,7 +141,7 @@ For each card, execute these phases in order:
141
141
  ### Phase 3.5 — QA Validation
142
142
 
143
143
  18. **Update tracker**: phase = "3.5-qa".
144
- 19. **Select QA profile** using the QA Profile Selector table above. Log the chosen profile and rationale in the tracker (1 line).
144
+ 19. **Select QA profile**: read the card's `review_profile` field (use verbatim); only compute from the QA Profile Selector table above when the field is absent (legacy card). Log the chosen profile and source (`from card` | `computed`) in the tracker (1 line).
145
145
  20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
146
146
  21. **If profile is LIGHT, BALANCED, or DEEP**: invoke the **`qa-sentinel`** agent (subagent_type: `qa-sentinel`) via Task tool with the following context:
147
147
 
@@ -297,7 +297,21 @@ Main repo: [/absolute/path/to/main/repo]
297
297
 
298
298
  ## QA Profile Selector
299
299
 
300
- Before Phase 3.5, determine the QA profile for each card by reading its YAML metadata. Use the **first matching rule** (priority order):
300
+ Before Phase 3.5, determine the review profile for each card.
301
+
302
+ **Primary path (deterministic — since v3.38.0): READ `review_profile` from the card YAML.**
303
+ The PRD `prd-card-writer` computes this field at authoring time (`prd-card-writer.md §
304
+ Rule C` — the SSOT) so the decision is made once, in the card, not re-interpreted here.
305
+ If the card has a `review_profile` ∈ {`skip`, `light`, `balanced`, `deep`}, **use it
306
+ verbatim** — do NOT recompute. Log `profile=<x> (from card)` in the tracker.
307
+
308
+ **Fallback path (legacy cards only): compute from the table below.** Cards authored before
309
+ v3.38.0 (or manually without the field) have no `review_profile`. Only then, derive it using
310
+ the **first matching rule** (priority order). Log `profile=<x> (computed — review_profile absent)`.
311
+
312
+ > ⚠️ This fallback table MUST stay in sync with `prd-card-writer.md § Rule C`, which is the
313
+ > SSOT. If you edit the rules, edit both. The two differ only in *when* they run (authoring
314
+ > time vs `/new` runtime), never in *what* they decide.
301
315
 
302
316
  | Profile | When to apply |
303
317
  |---------|--------------|
@@ -1176,7 +1190,7 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1176
1190
  ### Phase 3.5 — QA Validation
1177
1191
 
1178
1192
  18. **Update tracker**: phase = "3.5-qa".
1179
- 19. **Select QA profile** using the QA Profile Selector table above. Log the chosen profile and rationale in the tracker (1 line).
1193
+ 19. **Select QA profile**: READ the card's `review_profile` field (use verbatim); only compute from the QA Profile Selector table above when the field is absent (legacy card). Log the chosen profile and its source (`from card` | `computed`) in the tracker (1 line).
1180
1194
  20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
1181
1195
  21. **If profile is LIGHT**: SKIP qa-sentinel — Phase 2 step 8 already ran lint/tsc/test/build gates. Log "QA LIGHT skipped — gates already passed in Phase 2" in the tracker. Proceed to Phase 4.
1182
1196
  22. **If profile is BALANCED or DEEP**: invoke the **`qa-sentinel`** agent (subagent_type: `qa-sentinel`) via Task tool with the following context:
@@ -1215,7 +1229,7 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1215
1229
 
1216
1230
  **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.
1217
1231
 
1218
- **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 cost of a per-card Codex pass is acceptable; the cost of a missed blocker on a "low-risk" path (BUG-0530-class regressions) is not.
1232
+ **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.
1219
1233
 
1220
1234
  #### Step A — Detect (signal-logging only, NEVER gates the next step)
1221
1235
 
@@ -1276,26 +1290,40 @@ Log the detector output in the tracker for traceability. **This step never short
1276
1290
 
1277
1291
  For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH varies):
1278
1292
 
1279
- 0. **Select the review profile (deterministic — Review Profile Selector, since v3.35.0)** from
1280
- signals ALREADY computed (no new thresholds):
1281
- - **`light`** Step A matched **zero** high-risk triggers **AND** this card's QA profile
1282
- (Phase 3.5) ∈ {`skip`, `light`}.
1283
- - **`full`** ⟺ otherwise (any trigger matched, OR QA ∈ {`balanced`, `deep`}).
1284
-
1285
- `light` is **NOT** a skip: `/codexreview` still runs `code-reviewer` + Codex adversarial + the
1286
- Step 3 false-positive gate. It drops only the breadth agents (qa-sentinel, api-perf-cost-auditor,
1287
- doc-reviewer) and Step 3.5 CoVe — exactly the passes that yield ~nothing on a 0-trigger, QA-light
1288
- diff. The BUG-0530 invariant ("never miss a blocker on a low-risk path") holds because the Codex
1289
- adversarial pass the one that catches those always runs.
1290
- **ACTIVE since v3.37.0**: the selector above runs as written. Here `light` is an **early-feedback
1291
- optimization** for the per-card loop — NOT the merge-gate. Safety is guaranteed downstream: since
1292
- v3.37.0 the **Final review ALWAYS runs a single FULL `/codexreview` over the entire batch diff before
1293
- merge** (no N=1 skip, no scope reduction see "Final review Final-review FULL gate"). So every card
1294
- reviewed at `light` here still receives a full-depth review before merge; `light` shifts the breadth
1295
- passes (qa-sentinel, api-perf-cost-auditor, doc-reviewer) + CoVe from the per-card loop to that single
1296
- final full pass, it does not drop them from the merge gate. The BUG-0530 invariant still holds per-card
1297
- (Codex adversarial + `code-reviewer` + FP-gate always run in `light`). To make Phase 3.7 always-full
1298
- again: restore `profile = full` here (the final full gate is independent and stays regardless).
1293
+ 0. **Select the Codex review profile (deterministic — Review Profile Selector)** by mapping the
1294
+ card's review profile (read from the card's `review_profile` field per the QA Profile Selector
1295
+ above since v3.38.0; fallback-computed only for legacy cards) and the Step A detector:
1296
+ - **`light`** ⟺ the card's profile ∈ {`skip`, `light`} **AND** Step A matched **zero**
1297
+ high-risk triggers.
1298
+ - **`full`** ⟺ otherwise — i.e. the card's profile ∈ {`balanced`, `deep`}, **OR** any Step A
1299
+ trigger matched.
1300
+
1301
+ **Escalation-only invariant (since v3.38.0)**: the Step A detector runs on the ACTUAL diff and
1302
+ can only ever **escalate** `light` `full` (a high-risk path surfaced at implementation time
1303
+ that the card's authored profile didn't anticipate). It can NEVER downgrade `full` → `light`.
1304
+ The card's `review_profile` is the deterministic floor; the diff detector is the safety net on
1305
+ top of it.
1306
+
1307
+ `light` is **NOT** a skip: `/codexreview` still runs `code-reviewer` + the Step 3 false-positive
1308
+ gate. **Since v3.38.0 the per-card Codex adversarial pass is NO LONGER run at `light`** it is the
1309
+ prerogative of `full` and of the final cross-check. `light` drops the Codex adversarial pass AND the
1310
+ breadth agents (qa-sentinel, api-perf-cost-auditor, doc-reviewer) AND Step 3.5 CoVe leaving exactly
1311
+ `code-reviewer` + FP-gate, the cheap per-card pass that yields the early feedback worth having on a
1312
+ 0-trigger, QA-light diff. `full` is unchanged (Codex adversarial + the full agent set, minus the
1313
+ duplicate doc-reviewer).
1314
+ **Where the BUG-0530 invariant now lives.** Pre-v3.38.0 the per-card Codex adversarial was the
1315
+ "never miss a blocker on a low-risk path" guard. Two mechanisms now carry that guarantee instead,
1316
+ so dropping it from `light` is safe:
1317
+ 1. **Escalation-only (Step A)** — any high-risk trigger on the ACTUAL diff promotes `light` → `full`,
1318
+ so genuinely risky paths (auth/payment/permission/schema/…) STILL get per-card Codex adversarial.
1319
+ Only a 0-trigger, authored-`light` card defers it.
1320
+ 2. **Final-review FULL gate (since v3.37.0)** — the **Final review ALWAYS runs a single FULL
1321
+ `/codexreview` over the entire batch diff before merge** (no N=1 skip, no scope reduction — see
1322
+ "Final review → Final-review FULL gate"), and FULL includes Codex adversarial. So every line of
1323
+ every `light` card receives Codex adversarial at least once before merge.
1324
+ Net effect: `light` per-card = early `code-reviewer` feedback; the Codex adversarial review is paid
1325
+ once, at the final batch gate (or per-card the moment a risk trigger fires). To put per-card Codex
1326
+ back on `light`, re-add agent #5 to the `light` branch of `/codexreview` Step -0.5.
1299
1327
 
1300
1328
  Then dump the card diff (reviewer grounding) and write the lean contract `/codexreview` consumes:
1301
1329
  ```bash
@@ -1316,7 +1344,7 @@ For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH var
1316
1344
  ```
1317
1345
  ## Pre-Merge Codex Review
1318
1346
  - Triggered: unconditional (mandatory pre-merge gate)
1319
- - Profile: light | full — reason: <triggers=0, qa=light | trigger #N matched | qa=deep>
1347
+ - Profile: light | full — reason: <review_profile=<skip|light|balanced|deep> (from card | computed); triggers=0 | trigger #N matched (escalated light→full)>
1320
1348
  - Matched high-risk triggers: <list from detector, or "none">
1321
1349
  - Action: invoking /codexreview <CARD-ID> (per-card, pre-merge gate; lean contract written)
1322
1350
  ```
@@ -1330,8 +1358,9 @@ For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH var
1330
1358
 
1331
1359
  `/codexreview` Step -0.5 consumes `/tmp/codexreview-lean-<CARD-ID>.json`: reuses the Phase-1
1332
1360
  architecture baseline (no re-spawn), drops the duplicate doc-reviewer, and for `profile: light`
1333
- also drops qa-sentinel + api-perf-cost-auditor + Step 3.5 CoVe. Codex adversarial + Step 3
1334
- FP-gate + Step 4 report ALWAYS run. (`full` = standard pipeline minus the duplicate doc-reviewer.)
1361
+ also drops qa-sentinel + api-perf-cost-auditor + **the Codex adversarial pass** + Step 3.5 CoVe
1362
+ (since v3.38.0). `code-reviewer` + Step 3 FP-gate + Step 4 report ALWAYS run. (`full` = standard
1363
+ pipeline incl. Codex adversarial, minus the duplicate doc-reviewer.)
1335
1364
 
1336
1365
  3. **Read the consolidated report** from `/tmp/codexreview-report-<TIMESTAMP>.md`. Extract:
1337
1366
  - Verified BLOCKER count
@@ -1716,9 +1745,14 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
1716
1745
  git -C "$MAIN" fetch origin --quiet
1717
1746
  ```
1718
1747
 
1719
- 2. **Parse `[SYNC-DEFERRED]` markers** — scan the captured stdout from every `/mw` invocation in this batch (kept in the tracker under `## Worktree Merges`) for `[SYNC-DEFERRED] main repo HEAD=<branch>` lines. If present, surface to the user via `AskUserQuestion`:
1720
- - Question: `"Una o più merge worktree hanno deferito la sincronizzazione di local develop (main repo HEAD non era develop). Come riconcilio adesso?"`
1721
- - Options: `[Ora HEAD è develop ff-pull adesso]` / `[Lascia deferred (riconcilio io manualmente)]` / `[Mostra dettagli e fammi decidere]`.
1748
+ 2. **Parse `mw-docs` sync markers** — scan the captured stdout from every `/mw` invocation in this batch (kept in the tracker under `## Worktree Merges`):
1749
+ - **`[SYNC-DEFERRED] main repo HEAD=<branch>`** (main repo HEAD develop) surface via `AskUserQuestion`:
1750
+ - Question: `"Una o più merge worktree hanno deferito la sincronizzazione di local develop (main repo HEAD non era develop). Come riconcilio adesso?"`
1751
+ - Options: `[Ora HEAD è develop → ff-pull adesso]` / `[Lascia deferred (riconcilio io manualmente)]` / `[Mostra dettagli e fammi decidere]`.
1752
+ - **`[SYNC-NEEDS-DECISION] …`** (HEAD was develop but the ff was blocked by a **foreign** uncommitted file, or by a divergence/rebase conflict `/mw` would not auto-commit) — this is NEVER a passive note. Surface via `AskUserQuestion`:
1753
+ - Question: `"Il develop locale non si è sincronizzato: <dettaglio dal marker>. Come chiudo?"`
1754
+ - Options: `[Committa tu adesso (descrivi cosa)]` / `[Lo gestisco io — chiudi senza sync locale]` / `[Mostrami il diff e decidiamo]`.
1755
+ - **No marker** — `/mw` fast-forwarded (or auto-reconciled the framework telemetry log); nothing to parse.
1722
1756
 
1723
1757
  3. **Clean-tree assertion (BLOCKING)**:
1724
1758
  ```bash
@@ -2198,11 +2232,11 @@ After ALL agents in the group complete successfully:
2198
2232
 
2199
2233
  3c. **D.3c — Phase 2.6 E2E-Review (per-card)** — For EACH card in the group, honor the existing Gate table (skip when `features.has_e2e_review: false`, backend-only diff per the diff predicate documented in Phase 2.6, or card type `docs`/`chore`/`config`). For cards that pass the gate, invoke `/e2e-review` in programmatic mode with that card's payload. 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.
2200
2234
 
2201
- 4. **D.4 — QA gate (group)** — Select the HIGHEST QA profile across all cards in the group (e.g., if one card is BALANCED and another is DEEP, use DEEP). Invoke **qa-sentinel** once for the group.
2235
+ 4. **D.4 — QA gate (group)** — Read each card's `review_profile` field (fallback: compute via the QA Profile Selector table for legacy cards). Select the HIGHEST profile across all cards in the group (e.g., if one card is BALANCED and another is DEEP, use DEEP). Invoke **qa-sentinel** once for the group.
2202
2236
 
2203
2237
  4a. **D.4a — Per-card doc gate (consumes D.2, since v3.35.0)** — Do NOT re-spawn `doc-reviewer`. For EACH card in the group, take that card's doc findings from D.2's per-card-attributed output; if any exist, spawn a targeted fix-coder for that card only. (Previously D.4a re-ran doc-reviewer per card — a duplicate of D.2; collapsed to a single attributed D.2 pass. D.4b's per-card `/codexreview` also skips its doc-reviewer via the lean contract, so doc-review now runs once per group instead of ~3× per card.)
2204
2238
 
2205
- 4b. **D.4b — Pre-Merge Codex Review Gate (per-card, MANDATORY — UNCONDITIONAL)** — Invoke `/codexreview` for EACH card in the group, one at a time, BEFORE any commit. This mirrors Phase 3.7 of the sequential path and is non-skippable regardless of file paths or perceived risk. Apply the same fix sub-loop: if the consolidated report shows verified BLOCKER/HIGH findings, spawn a fix-coder and re-run `/codexreview <CARD-ID>` (max 2 retries per 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: light|full` from (0 triggers + QA {skip,light}). LIGHT still runs Codex adversarial + code-reviewer + FP-gate. The Review Profile Selector is **ACTIVE since v3.37.0** — same status as sequential Phase 3.7 Step C above: `light` is per-card early feedback, and the merge-gate safety 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 per-card always-full again, restore `profile = full`; the final full gate stays regardless.
2239
+ 4b. **D.4b — Pre-Merge Codex Review Gate (per-card, MANDATORY — UNCONDITIONAL)** — Invoke `/codexreview` for EACH card in the group, one at a time, BEFORE any commit. This mirrors Phase 3.7 of the sequential path and is non-skippable regardless of file paths or perceived risk. Apply the same fix sub-loop: if the consolidated report shows verified BLOCKER/HIGH findings, spawn a fix-coder and re-run `/codexreview <CARD-ID>` (max 2 retries per 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: light|full` derived from the card's `review_profile` (`skip`/`light` → `light`, `balanced`/`deep` → `full`; since v3.38.0 read from the card, not recomputed) with the same **escalation-only** rule: a Step A high-risk trigger on the actual diff promotes `light` → `full`, never the reverse. LIGHT runs `code-reviewer` + FP-gate only — the per-card **Codex adversarial pass is dropped at `light` since v3.38.0** (prerogative of `full` + the final cross-check). The Review Profile Selector is **ACTIVE since v3.37.0** — same status as sequential Phase 3.7 Step C above: `light` is per-card early feedback, and the merge-gate safety 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 per-card always-full again, restore `profile = full`; the final full gate stays regardless.
2206
2240
 
2207
2241
  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):
2208
2242
  ```bash
@@ -108,6 +108,20 @@ blocks: [{{card IDs}}]
108
108
 
109
109
  estimated_complexity: {{LOW|MEDIUM|HIGH}}
110
110
 
111
+ # review_profile — REQUIRED. Decides the per-card review DEPTH deterministically,
112
+ # at PRD authoring time, so /new READS it instead of re-deriving it at runtime.
113
+ # One field drives BOTH QA depth (Phase 3.5) and the Codex profile (Phase 3.7).
114
+ # skip → docs/chore/config or pure-cosmetic cards; no QA/Codex depth needed
115
+ # light → bugfix/refactor, ≤3 files, no high-risk areas (NEVER for feature/enhancement)
116
+ # balanced → default for feature/enhancement, or bugfix/refactor with breadth/risk
117
+ # deep → api+data, auth/payment/permission/schema/migration, ≥3 new/modified
118
+ # data_fields, db_indexes, AC count > 5, or HIGH estimated_complexity
119
+ # Auto-computed by prd-card-writer (§ Review Profile Rules — the SSOT). You MAY
120
+ # override it by hand to force a deeper/shallower review on a specific card.
121
+ # /new maps skip|light → Codex `light`, balanced|deep → Codex `full` (Phase 3.7);
122
+ # a high-risk path in the actual diff can only ESCALATE the Codex profile, never lower it.
123
+ review_profile: {{skip|light|balanced|deep}}
124
+
111
125
  # Parallelization metadata (auto-computed by /prd backlog phase)
112
126
  parallel_group: {{N}} # Layer di esecuzione: 0 = prima, 1 = dopo layer 0, etc.
113
127
  # Card nello stesso gruppo possono girare in parallelo
@@ -116,6 +116,11 @@ blocks: []
116
116
 
117
117
  estimated_complexity: {{LOW|MEDIUM|HIGH}}
118
118
 
119
+ # review_profile — epics are trackers with NO code-touching work, so review depth
120
+ # is N/A. Always `skip` (consistent with owner_agent: "" on epics). The real
121
+ # review depth lives on the child cards.
122
+ review_profile: skip
123
+
119
124
  parallel_group: 0
120
125
 
121
126
  # =============================================================================
@@ -216,6 +216,7 @@ The `prd-card-writer` agent owns the entire card writing pipeline:
216
216
  - `execution_strategy` block on epic parent card
217
217
  - State file update with card list and matrices
218
218
  - `env_vars` field: per ogni card che introduce/modifica/rimuove env vars (rilevabile da PRD Section 6 o da requirements che menzionano `process.env`, segreti, API keys, feature flags), popola il campo con `action: new|modified|removed`, `scope`, `required`, `note`. Se la card non tocca env vars, scrivi `env_vars: []`.
219
+ - `review_profile` field: deterministic per-card review depth (`skip|light|balanced|deep`) computed via `prd-card-writer.md § Rule C` from the card's own metadata (type, areas, data_fields, db_indexes, AC count, estimated_complexity). This materializes the review decision at authoring time so `/new` reads it instead of re-deriving it. Epics always get `review_profile: skip`. Honor any explicit author override already present in the YAML.
219
220
 
220
221
  ### What stays in the main context
221
222
 
@@ -24,7 +24,16 @@ Mark task 5 as `in_progress`.
24
24
  - The check is intentionally a soft gate: substrings like "API contract per il mock" or "consumes the auth state from `useAuth()`" are legitimate UI references. The WARN exists to prompt human review, not to block.
25
25
  - Exception (no WARN): the marker appears INSIDE a quoted string that explicitly says "consume", "mock", "contract reference", or "exposed by sibling card" — those are UI cards reading an upstream contract, which is expected.
26
26
 
27
- **Gate**: every card has `owner_agent` in the enum. WARN entries from check (b) are noted in the audit log; user may accept them after review.
27
+ c. **`review_profile` enum check (BLOCKING)** read the `review_profile` field on each child card. It MUST equal one of:
28
+ ```
29
+ skip | light | balanced | deep
30
+ ```
31
+ - **Missing or empty** = **BLOCKER** — the card-writer must compute it via `prd-card-writer.md § Rule C` (the SSOT mapping table). Message: `"Card <ID> has no review_profile — compute it from Rule C (skip|light|balanced|deep) before commit."`
32
+ - **Out-of-enum value** = **BLOCKER**. Message: `"Card <ID> has review_profile: '<value>' — must be one of {skip, light, balanced, deep}."`
33
+ - **Consistency WARN (soft)**: a `feature`/`enhancement` card with `review_profile: light` violates Rule C ("never light for feature/enhancement"). Log `"[REVIEW-PROFILE-WARN] Card <ID> is feature/enhancement but review_profile: light — Rule C floors these at balanced."` and bump to `balanced` unless the author left an explicit override note.
34
+ - **Epics**: `review_profile` MUST be `skip` (trackers have no code work). Any other value = WARN, normalize to `skip`.
35
+
36
+ **Gate**: every card has `owner_agent` AND `review_profile` in their enums. WARN entries from checks (b)/(c) are noted in the audit log; user may accept them after review.
28
37
 
29
38
  1. **Field Name Audit (runs BEFORE audit agents)** — for each generated card:
30
39
 
@@ -73,9 +82,13 @@ created by Step 1 (HARD RULE 17). `$WORKTREE_PATH` is set in the state file.
73
82
  in parallel. The rebase in step 8 below brings the worktree up to the latest
74
83
  `origin/develop` BEFORE the merge, so two parallel PRDs ending at the same
75
84
  time produce a clean append-only diff in most cases. If the rebase reports
76
- conflicts on these two files specifically, the `worktree-manager mw-docs`
77
- protocol stops and asks for manual resolution do NOT auto-strip merge
78
- markers on structured files like these.
85
+ conflicts on these two files, `worktree-manager mw-docs` does **not** ask
86
+ immediately: it strips the markers ("keep both sides", which on append-only
87
+ registries is the correct additive result) and then runs a structural
88
+ validation. The merge proceeds automatically when the validation passes. It
89
+ escalates to the user **only** in the rare case where both PRDs modified the
90
+ same row and the validation fails — i.e. a conflict that genuinely cannot be
91
+ auto-resolved. See `/mw` step 4b "Structured registries" row.
79
92
 
80
93
  ### Commit (inside the worktree)
81
94
 
@@ -110,9 +123,18 @@ created by Step 1 (HARD RULE 17). `$WORKTREE_PATH` is set in the state file.
110
123
  ### Merge into develop (worktree-manager mw-docs)
111
124
 
112
125
  9. **Invoke `worktree-manager` programmatic mw-docs immediately** — no
113
- confirmation prompt. The user opted into the full PRD pipeline when they
114
- ran `/prd`; chiedere conferma a fine sessione è friction inutile e rompe
115
- il "seamless" che è il punto della v3.22.0.
126
+ confirmation prompt, no "vuoi che mergi e pulisca il worktree?" question.
127
+ The user opted into the full PRD pipeline when they ran `/prd`; chiedere
128
+ conferma a fine sessione è friction inutile e rompe il "seamless" che è il
129
+ punto della v3.22.0. Merge **and** worktree cleanup run automatically.
130
+
131
+ **The ONLY thing that stops the automatic merge is a conflict `mw-docs`
132
+ genuinely cannot auto-resolve** (a code/test conflict, or a structured
133
+ registry whose strip+validate failed — see step 10). Everything `mw-docs`
134
+ can auto-resolve (additive docs/YAML/JSONL, append-only registries that pass
135
+ validation) merges with zero questions. Do NOT pre-empt the merge with a
136
+ confirmation gate "just in case there might be conflicts" — let `mw-docs`
137
+ run and only surface what it actually reports as unresolvable.
116
138
 
117
139
  The merge is recoverable: if something goes wrong post-merge the user can
118
140
  `git revert` on develop just like any other commit. The hard-to-reverse
@@ -141,9 +163,10 @@ created by Step 1 (HARD RULE 17). `$WORKTREE_PATH` is set in the state file.
141
163
  - Conflict auto-resolution table (see `/mw` step 4b): additive docs/yaml and
142
164
  append-only `.jsonl` files auto-resolve; **structured registries**
143
165
  (`project-status.md`, `ssot-registry.md`, `field-registry.*`,
144
- `traceability-matrix.md`, `REGISTRY.md`) abort the rebase and report —
145
- these must be resolved manually because blindly stripping markers would
146
- corrupt their internal structure.
166
+ `traceability-matrix.md`, `REGISTRY.md`) are auto-resolved by strip +
167
+ structural validation, and only abort (escalating to the user) when the
168
+ validation fails the rare same-row collision. Code / test / fixture
169
+ conflicts always abort and escalate.
147
170
  - Merge via the configured `git.merge_strategy` (`pr` or `local-push`).
148
171
  - Cleanup: `git worktree remove` + `git branch -d` + registry entry removal.
149
172
  - Local develop ref sync (only if main repo HEAD is already `develop`).
@@ -161,6 +184,45 @@ the state file (now on `develop` via the merge) shows `completed`.
161
184
 
162
185
  Mark task 5 as `completed`.
163
186
 
187
+ ### Step 7.5 — Workspace hygiene & finalization (BLOCKING — the run MUST conclude clean)
188
+
189
+ **Why this exists (v3.39.0).** A PRD run used to end by handing the user a list of
190
+ "azioni tue, non bloccanti" — an uncommitted file blocking the local `develop`
191
+ fast-forward, a remote branch left undeleted. That is a half-finished process.
192
+ `/prd` now closes the loop exactly like `/new` Phase 6c: **no residue is ever
193
+ surfaced as a passive manual TODO.** Every leftover is either auto-resolved or put
194
+ behind ONE explicit `AskUserQuestion` gate.
195
+
196
+ Scan the captured `mw-docs` stdout (the merge step above) for the structured
197
+ markers it can emit, then act:
198
+
199
+ 1. **`[SYNC-NEEDS-DECISION] …`** — the local `develop` could not fast-forward and
200
+ the blocker is a **foreign** uncommitted file (one this run does not own), or a
201
+ genuine divergence/rebase conflict. Do NOT auto-commit foreign work. Raise ONE
202
+ `AskUserQuestion`:
203
+ - Question: `"Il develop locale non si è sincronizzato: <dettaglio dal marker>. Come chiudo?"`
204
+ - Options: `[Committa tu adesso (descrivi cosa)]` / `[Lo gestisco io — chiudi senza sync locale]` / `[Mostrami il diff e decidiamo]`.
205
+ Act on the answer in this turn. Never leave it as a printed note.
206
+
207
+ 2. **`[SYNC-DEFERRED] …`** (main repo HEAD ≠ `develop`) — fetch already updated
208
+ `refs/remotes/origin/develop`. If the user's HEAD is now `develop`, run
209
+ `git -C "$MAIN" pull --ff-only origin develop`. Otherwise raise ONE
210
+ `AskUserQuestion` (`[ff-pull adesso]` / `[Lascio deferred, riconcilio io]`).
211
+
212
+ 3. **No marker** — `mw-docs` already fast-forwarded (or auto-reconciled the
213
+ framework telemetry log). Nothing to do; the tree is clean.
214
+
215
+ 4. **Remote feature branch** — `mw-docs` deletes the merged remote branch as
216
+ routine cleanup (see AGENTS.md § branch deletion: deleting an **already-merged**
217
+ feature branch is NOT the gated "branch deletion" that needs owner approval).
218
+ If for any reason the deletion was blocked, do NOT print "puoi cancellarlo a
219
+ mano": run `git push origin --delete <branch>` now, and only if THAT is denied
220
+ raise ONE `AskUserQuestion`.
221
+
222
+ **Gate:** `git -C "$MAIN" status --porcelain` for framework-owned paths is empty,
223
+ no `[SYNC-NEEDS-DECISION]` marker is left unhandled, and the merged remote branch
224
+ is gone (or its deletion is explicitly user-deferred).
225
+
164
226
  ### Final output
165
227
 
166
228
  Print final summary:
@@ -170,6 +232,13 @@ Print final summary:
170
232
  - Card IDs created
171
233
  - Branch & merge strategy used
172
234
  - PR number (if `strategy = pr`) or merge SHA (if `local-push`)
173
- - Confirmation that the worktree was cleaned up
235
+ - Confirmation that the worktree was cleaned up AND the remote branch was deleted
236
+
237
+ **HARD RULE — no passive deferral.** The final summary MUST NOT contain a "azioni
238
+ tue / note non bloccanti / puoi farlo a mano" section. If something genuinely needs
239
+ the user, it was already raised as an `AskUserQuestion` in Step 7.5 and acted on —
240
+ it does not reappear here as a TODO. A run that prints "il develop locale non si è
241
+ fast-forwardato, gestisci tu il file e poi pulla" has FAILED Step 7.5 — go back and
242
+ resolve it before printing the summary.
174
243
 
175
244
  Display completed Progress Bar.
@@ -865,8 +865,44 @@ PR_NUMBER=""
865
865
  # HEAD alone and they'll pull next time.
866
866
  CURRENT_BRANCH=$(git -C "$MAIN" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
867
867
  if [ "$CURRENT_BRANCH" = "develop" ]; then
868
- git -C "$MAIN" pull --ff-only origin develop || \
869
- echo "⚠️ Could not fast-forward main repo develop (uncommitted work?). Leaving as-is."
868
+ if git -C "$MAIN" pull --ff-only origin develop 2>/dev/null; then
869
+ echo " Main repo develop fast-forwarded to origin/develop."
870
+ else
871
+ # FF blocked. NEVER leave this as a passive "Leaving as-is" TODO for the user
872
+ # (v3.39.0 — the finalizer MUST conclude). The cause is almost always an
873
+ # uncommitted append to the framework-owned telemetry log left by a prior run.
874
+ # Partition the dirty tree:
875
+ # - framework-owned artifact (docs/metrics/skill-runs.jsonl) → auto-reconcile
876
+ # (commit + rebase) so the ff completes with zero data loss;
877
+ # - ANY foreign file → emit a decision marker the orchestrator MUST convert
878
+ # into ONE explicit user gate. Never auto-commit work this run did not own.
879
+ DIRTY=$(git -C "$MAIN" status --porcelain --untracked-files=no | sed 's/^...//')
880
+ FOREIGN=""
881
+ OWNED=""
882
+ for f in $DIRTY; do
883
+ case "$f" in
884
+ docs/metrics/skill-runs.jsonl) OWNED="$OWNED $f" ;;
885
+ *) FOREIGN="$FOREIGN $f" ;;
886
+ esac
887
+ done
888
+ if [ -n "$FOREIGN" ]; then
889
+ echo "[SYNC-NEEDS-DECISION] main repo develop cannot fast-forward; foreign uncommitted files:${FOREIGN} — orchestrator MUST raise ONE explicit user gate (commit / user-handles), never a passive note."
890
+ elif [ -n "$OWNED" ]; then
891
+ # Only framework-owned telemetry is dirty → reconcile autonomously, lossless.
892
+ git -C "$MAIN" add docs/metrics/skill-runs.jsonl
893
+ git -C "$MAIN" commit -m "chore(metrics): reconcile skill-runs telemetry before develop sync" --quiet
894
+ if git -C "$MAIN" pull --rebase origin develop 2>/dev/null; then
895
+ git -C "$MAIN" push origin develop 2>/dev/null \
896
+ && echo "✅ Reconciled stale metrics log + synced develop to origin." \
897
+ || echo "✅ Reconciled stale metrics log (local develop 1 commit ahead; syncs on next push). Tree clean."
898
+ else
899
+ git -C "$MAIN" rebase --abort 2>/dev/null || true
900
+ echo "[SYNC-NEEDS-DECISION] metrics rebase conflict on develop — orchestrator MUST raise ONE explicit user gate."
901
+ fi
902
+ else
903
+ echo "[SYNC-NEEDS-DECISION] main repo develop cannot fast-forward and the working tree is clean (diverged?) — orchestrator MUST raise ONE explicit user gate."
904
+ fi
905
+ fi
870
906
  else
871
907
  echo "ℹ️ Main repo HEAD is '$CURRENT_BRANCH' — not switching. Next manual `git pull` on develop will sync."
872
908
  git -C "$MAIN" fetch origin develop --quiet
@@ -905,8 +941,17 @@ git branch -d "$BRANCH"
905
941
  ```
906
942
 
907
943
  ```bash
908
- # 3. Delete the remote branch (optional may not exist if never pushed)
909
- git push origin --delete "$BRANCH" 2>/dev/null || true
944
+ # 3. Delete the remote branch. The branch is ALREADY MERGED into develop at this
945
+ # point, so this is routine cleanup — NOT the gated "branch deletion" that needs
946
+ # owner approval (see AGENTS.md § branch deletion). Report the outcome; never
947
+ # degrade a failure into a passive "puoi cancellarlo a mano" note handed to the user.
948
+ if git push origin --delete "$BRANCH" 2>/dev/null; then
949
+ echo "✅ Remote branch '$BRANCH' deleted (merged → routine cleanup)."
950
+ else
951
+ echo "ℹ️ Remote branch '$BRANCH' not deleted (already gone, or the deletion was denied)."
952
+ echo " If denied: this is a merged branch — retry the delete; only if it is STILL"
953
+ echo " denied must the orchestrator raise ONE explicit user gate, never a passive TODO."
954
+ fi
910
955
  ```
911
956
 
912
957
  ```bash
@@ -923,12 +968,15 @@ Remove the entry from `.worktrees/registry.json`.
923
968
  ```
924
969
  Merge complete:
925
970
  Card: <CARD-ID>
926
- Branch: <BRANCH> (deleted on remote; local-cleanup may have skipped if checked out elsewhere)
971
+ Branch: <BRANCH> (deleted on remote merged branch deletion is routine cleanup, never gated)
927
972
  Strategy: <pr | local-push>
928
973
  PR: #<PR_NUMBER> merged via `gh pr merge` ← only in `pr` strategy
929
974
  Push: fast-forward to origin/develop ← only in `local-push` strategy
930
975
  Worktree: <WORKTREE_PATH> (removed)
931
- develop: remote up to date; local main-repo synced only if HEAD was already develop
976
+ develop: remote up to date; local main-repo synced (auto-reconciled framework
977
+ telemetry if it blocked the ff). Any [SYNC-NEEDS-DECISION] /
978
+ [SYNC-DEFERRED] marker above is for the orchestrator to gate on —
979
+ NOT a residue to hand the user as a manual TODO.
932
980
  ```
933
981
 
934
982
  ---
@@ -104,9 +104,9 @@ Conflict steps (must follow in order):
104
104
  - MUST use commit format `[FEAT-XXX] Brief description` or adapt to your project's convention; keep commits small/traceable.
105
105
  - MUST NOT commit without updated docs or with failing lint/type checks. Full build is required only before opening a PR, not before every commit.
106
106
  - MUST pre-sync: `git fetch origin`, clean status, confirm branch; use `git pull --ff-only` unless approved.
107
- - MUST get owner approval before force push/reset/branch deletion; create a safety tag `backup/<YYYYMMDD>-<reason>`.
107
+ - MUST get owner approval before force push/reset, and before deleting an **unmerged** branch; create a safety tag `backup/<YYYYMMDD>-<reason>`. Deleting a feature branch that is **already merged** into `develop` is routine cleanup (it carries no unmerged work) and does NOT require a separate approval — the merge skill deletes it automatically.
108
108
  - MUST NEVER push directly to `main`; all changes reach `main` via PR (release from `develop` or hotfix merge). Pre-push hook enforces this.
109
- - MUST push working branch and keep `main` merge owner-controlled; prune remote branches only when instructed.
109
+ - MUST push working branch and keep `main` merge owner-controlled; the merge skill prunes a feature branch's own remote ref on successful merge into `develop` (routine), but pruning OTHER remote branches happens only when instructed.
110
110
  - MUST run testing gates before DONE: run tests (if exist), run build, and CI checks on PR; manual validation is REQUIRED for local mode and OPTIONAL for cloud mode.
111
111
  - MUST pass pre-commit hooks (linting, type checking, markdown lint, build); bypass (`--no-verify`) only for documented emergencies.
112
112
  - MUST use API versioning for breaking changes: create new version, deprecate old with appropriate headers, minimum sunset period; see project-specific API migration docs.
@@ -123,3 +123,10 @@ metadata:
123
123
  created: YYYY-MM-DD
124
124
  updated: YYYY-MM-DD
125
125
  estimated_effort: "" # S | M | L | XL
126
+ # review_profile — decides the per-card review depth deterministically.
127
+ # /new reads this instead of re-deriving it at runtime; one field drives both
128
+ # QA depth (Phase 3.5) and the Codex profile (Phase 3.7).
129
+ # skip | light | balanced | deep
130
+ # Auto-computed by prd-card-writer for PRD-generated cards; set it by hand here
131
+ # when authoring a card manually (omit to let /new fall back to runtime compute).
132
+ review_profile: "" # skip | light | balanced | deep
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "3.37.0",
3
+ "version": "3.39.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"