baldart 3.40.0 → 4.0.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 +51 -0
- package/README.md +1 -1
- package/VERSION +1 -1
- package/framework/.claude/agents/REGISTRY.md +74 -24
- package/framework/.claude/agents/api-perf-cost-auditor.md +12 -5
- package/framework/.claude/agents/code-reviewer.md +30 -23
- package/framework/.claude/agents/codebase-architect.md +47 -43
- package/framework/.claude/agents/coder.md +29 -18
- package/framework/.claude/agents/doc-reviewer.md +55 -28
- package/framework/.claude/agents/plan-auditor.md +77 -12
- package/framework/.claude/agents/prd-card-writer.md +43 -13
- package/framework/.claude/agents/prd.md +22 -3
- package/framework/.claude/agents/qa-sentinel.md +75 -29
- package/framework/.claude/agents/security-reviewer.md +65 -10
- package/framework/.claude/agents/senior-researcher.md +8 -1
- package/framework/.claude/agents/ui-expert.md +22 -7
- package/framework/.claude/commands/check.md +31 -11
- package/framework/.claude/commands/codexreview.md +48 -29
- package/framework/.claude/commands/new.md +29 -328
- package/framework/.claude/commands/qa.md +62 -37
- package/framework/.claude/skills/context-primer/SKILL.md +29 -8
- package/framework/.claude/skills/doc-writing-for-rag/SKILL.md +36 -36
- package/framework/.claude/skills/frontend-design/SKILL.md +10 -8
- package/framework/.claude/skills/new/SKILL.md +413 -302
- package/framework/.claude/skills/prd/SKILL.md +67 -38
- package/framework/.claude/skills/prd/assets/card-template.yml +22 -26
- package/framework/.claude/skills/prd/assets/epic-template.yml +5 -5
- package/framework/.claude/skills/prd/assets/state-template.md +25 -3
- package/framework/.claude/skills/prd/references/api-perf-gate.md +143 -33
- package/framework/.claude/skills/prd/references/audit-phase.md +48 -34
- package/framework/.claude/skills/prd/references/backlog-phase.md +38 -11
- package/framework/.claude/skills/prd/references/discovery-phase.md +121 -44
- package/framework/.claude/skills/prd/references/impact-analysis.md +127 -23
- package/framework/.claude/skills/prd/references/prd-add-phase.md +18 -214
- package/framework/.claude/skills/prd/references/prd-writing-phase.md +52 -42
- package/framework/.claude/skills/prd/references/research-phase.md +105 -19
- package/framework/.claude/skills/prd/references/ui-design-phase.md +20 -8
- package/framework/.claude/skills/prd/references/validation-phase.md +97 -72
- package/framework/.claude/skills/prd-add/SKILL.md +70 -20
- package/framework/.claude/skills/simplify/SKILL.md +22 -12
- package/framework/.claude/skills/ui-design/SKILL.md +26 -7
- package/framework/.claude/skills/webapp-testing/SKILL.md +6 -4
- package/framework/.claude/skills/worktree-manager/SKILL.md +206 -143
- package/framework/agents/coding-standards.md +85 -0
- package/framework/agents/index.md +2 -1
- package/framework/agents/skills-mapping.md +85 -82
- package/framework/agents/testing.md +28 -0
- package/framework/templates/baldart.config.template.yml +29 -7
- package/package.json +1 -1
- package/src/commands/configure.js +43 -9
- package/framework/.claude/skills/prd-add/references/impact-analysis.md +0 -233
|
@@ -16,7 +16,7 @@ description: >
|
|
|
16
16
|
|
|
17
17
|
## Project Context
|
|
18
18
|
|
|
19
|
-
**Reads from `baldart.config.yml`:** `paths.backlog_dir`, `paths.references_dir`.
|
|
19
|
+
**Reads from `baldart.config.yml`:** `paths.backlog_dir`, `paths.references_dir`, `git.trunk_branch` (integration trunk; default `develop`), `git.merge_strategy`, `paths.high_risk_modules` (risk-detector path list), `paths.metrics` (default `docs/metrics`), `stack.language` / `stack.database` / `stack.deployment` (gate guards), and `features.has_e2e_review` / `features.has_design_system` / `features.has_lsp_layer`.
|
|
20
20
|
**Gated by features:** `features.has_backlog` (skill REFUSES to run when `false` — this orchestrator operates on backlog cards by definition).
|
|
21
21
|
**Overlay:** loads `.baldart/overlays/new.md` if present — project-specific canonical-docs registry (e.g. ssot-registry, linking-protocol guides), tooling paths (e.g. validation scripts).
|
|
22
22
|
**On missing/empty keys:** ask the user; do not assume defaults. See `framework/agents/project-context.md` § 3.
|
|
@@ -49,7 +49,7 @@ This file is your single source of truth — if your context gets compacted or y
|
|
|
49
49
|
|
|
50
50
|
### Tracking file format
|
|
51
51
|
|
|
52
|
-
At batch start, create `/tmp/batch-tracker-<FIRST-CARD-ID>.md` with:
|
|
52
|
+
At batch start — **before Phase 0 runs** (Phase 0 step 1 writes to the `## Worktree` section and Phase 0 step 5 writes the phase log, so the file MUST already exist) — create `/tmp/batch-tracker-<FIRST-CARD-ID>.md` with:
|
|
53
53
|
|
|
54
54
|
```markdown
|
|
55
55
|
# Batch Run: [CARD-IDS]
|
|
@@ -61,14 +61,17 @@ Started: [timestamp]
|
|
|
61
61
|
Total cards: [N]
|
|
62
62
|
|
|
63
63
|
## Workspace Snapshot
|
|
64
|
-
(none — Phase 0 will populate if
|
|
64
|
+
(none — Phase 0 will populate if the main repo had uncommitted work; the stash entry, when present, is recorded by its MESSAGE label, never a positional `stash@{N}`)
|
|
65
65
|
|
|
66
66
|
## Worktree
|
|
67
67
|
Branch: [feat/FEAT-XXXX-slug]
|
|
68
|
+
Slug: [the slug used to derive Branch/Path — see Pre-flight step 4]
|
|
68
69
|
Path: [.worktrees/feat-FEAT-XXXX-slug]
|
|
69
70
|
Port: [from registry]
|
|
71
|
+
Created: [ISO-8601 timestamp the worktree was created — Pre-flight step 5 backfills; Phase 8 cycle_time_mins start anchor]
|
|
70
72
|
Group parent: [FEAT-XXXX or "standalone"]
|
|
71
73
|
Main repo: [/absolute/path/to/main/repo]
|
|
74
|
+
Trunk branch: [resolved git.trunk_branch — Phase 0 step 0 populates]
|
|
72
75
|
|
|
73
76
|
## Card Queue
|
|
74
77
|
- [ ] CARD-001 — [title from backlog]
|
|
@@ -109,7 +112,7 @@ Main repo: [/absolute/path/to/main/repo]
|
|
|
109
112
|
- Test results (new + existing count, pass/fail)
|
|
110
113
|
- Fix cycles count
|
|
111
114
|
- UX testing result (PASS/FAIL/SKIP + test file path if written)
|
|
112
|
-
- QA result (profile used: skip/light/balanced/deep | verdict: PASS/FAIL/SKIP | confidence % |
|
|
115
|
+
- QA result (profile used: skip/light/balanced/deep | verdict: PASS/FAIL/SKIP | confidence % | failing gates: which of lint/tsc/test/build/markdownlint, or "none")
|
|
113
116
|
- QA findings file (e.g. `/qa/FEAT-XXXX.md` or "skipped")
|
|
114
117
|
- **card_status: DONE (verified)** — confirms the backlog YAML was updated and re-read to verify
|
|
115
118
|
- **When blocked**: log the blocker in `## Issues & Flags`.
|
|
@@ -125,7 +128,11 @@ Main repo: [/absolute/path/to/main/repo]
|
|
|
125
128
|
|
|
126
129
|
**Steps:**
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
0. **Feature gate + config resolution (BLOCKING)** — before anything else:
|
|
132
|
+
- Read `features.has_backlog` from `baldart.config.yml`. If it is `false` (or the key is absent and the user confirms there is no backlog), this skill REFUSES to run: print "`/new` operates on backlog cards and requires `features.has_backlog: true` — run `npx baldart configure` to enable." and HALT. Do NOT proceed to step 1.
|
|
133
|
+
- Resolve `$TRUNK` = `git.trunk_branch` from `baldart.config.yml` (default `develop` only when the key is absent). Persist it as `Trunk branch:` in the tracker `## Worktree` section. **Every later Phase 0 / Phase 6c bash snippet that references the integration trunk MUST use `$TRUNK`, never a baked-in `develop`.** Begin every later consumer with a guard: if `$TRUNK` is empty → HALT with "Trunk branch unresolved — re-read `git.trunk_branch` from config".
|
|
134
|
+
|
|
135
|
+
1. **Resolve `$MAIN`** — the absolute path of the main repo (not a worktree). If `/new` was invoked from inside a worktree, walk up to the parent repo via `git rev-parse --show-superproject-working-tree` or `git worktree list` until you find the non-worktree root. Persist as `Main repo:` in the tracker `## Worktree` section. **Write `$MAIN` to the tracker the moment it is computed** — every later consumer (Phase 6c, Phase 6b) MUST re-read it from the tracker and HALT with "`$MAIN` absent from tracker" if the field is missing or empty, never silently use an undefined `$MAIN` (it does not survive context compaction).
|
|
129
136
|
|
|
130
137
|
2. **Fetch remote state**:
|
|
131
138
|
```bash
|
|
@@ -139,41 +146,40 @@ Main repo: [/absolute/path/to/main/repo]
|
|
|
139
146
|
If the output is non-empty, invoke `AskUserQuestion`:
|
|
140
147
|
- Question: `"Main repo ($MAIN) ha modifiche non committate prima di partire con la batch. Come procedo?"`
|
|
141
148
|
- Options (max 4):
|
|
142
|
-
1. **"Stash automatico (restore in Phase 6c)"** —
|
|
149
|
+
1. **"Stash automatico (restore in Phase 6c)"** — `$MAIN` is the main checkout (NOT a worktree), so a stash here is safe. Run `git -C "$MAIN" stash push -u -m "baldart-new-phase0-<FIRST-CARD-ID>-<timestamp>"` and write the **stash MESSAGE label** (`baldart-new-phase0-<FIRST-CARD-ID>-<timestamp>`) to the tracker under `## Workspace Snapshot: <message-label> (created <timestamp>)`. Phase 6c resolves the stash by this message — NEVER by a positional `stash@{N}`, because other stashes pushed during the batch (on the main checkout) would shift the index. Do NOT record `stash@{0}`.
|
|
143
150
|
2. **"Committa adesso (apri editor)"** — halt the batch with a clear message asking the user to commit in their terminal and re-invoke `/new`. Do NOT proceed to step 4.
|
|
144
151
|
3. **"Procedi senza stash (lavoro mio, lo gestisco io)"** — explicit user override. Log in tracker: `## Workspace Snapshot: dirty-tree override @ <timestamp> — user accepted responsibility`. Phase 6c will still check post-merge state but will NOT attempt restore.
|
|
145
152
|
4. **"Abort batch"** — halt the batch, leave the tracker file in place, exit.
|
|
146
153
|
|
|
147
154
|
Do NOT silently proceed. Do NOT auto-stash without the user picking option 1.
|
|
148
155
|
|
|
149
|
-
4. **Divergence gate (BLOCKING)** — compare local `
|
|
156
|
+
4. **Divergence gate (BLOCKING)** — compare local `$TRUNK` against `origin/$TRUNK` (the trunk resolved in step 0):
|
|
150
157
|
```bash
|
|
151
|
-
git -C "$MAIN" rev-list --left-right --count origin
|
|
158
|
+
git -C "$MAIN" rev-list --left-right --count "origin/$TRUNK...$TRUNK"
|
|
152
159
|
```
|
|
153
160
|
The output is `<behind>\t<ahead>`. Branch on the result:
|
|
154
161
|
|
|
155
162
|
- **`0\t0`** — synchronized. Proceed to step 5.
|
|
156
163
|
- **`N\t0`** (only behind, N > 0) — invoke `AskUserQuestion`:
|
|
157
|
-
- Question: `"Local
|
|
164
|
+
- Question: `"Local $TRUNK è behind origin/$TRUNK di N commit. Come procedo?"`
|
|
158
165
|
- Options: `[Fast-forward pull adesso]` / `[Procedi senza pull]` / `[Abort]`.
|
|
159
|
-
- On `Fast-forward pull adesso`: if `$MAIN` HEAD ==
|
|
166
|
+
- On `Fast-forward pull adesso`: if `$MAIN` HEAD == `$TRUNK`, run `git -C "$MAIN" pull --ff-only origin "$TRUNK"`; otherwise log "main HEAD is `<branch>` — fetch already updated `refs/remotes/origin/$TRUNK`, local `$TRUNK` ref will be reconciled in Phase 6c".
|
|
160
167
|
- **`0\tM`** (only ahead, M > 0 — UNPUSHED LOCAL COMMITS, this is the FEAT-0006 pattern) — invoke `AskUserQuestion`:
|
|
161
|
-
- Question: `"Local
|
|
162
|
-
- Show the commit list inline: `git -C "$MAIN" log --oneline origin
|
|
163
|
-
- Options: `[Push adesso (git push origin
|
|
168
|
+
- Question: `"Local $TRUNK è ahead di origin/$TRUNK di M commit (commit locali non pushati). Cosa faccio?"`
|
|
169
|
+
- Show the commit list inline: `git -C "$MAIN" log --oneline "origin/$TRUNK..$TRUNK"`.
|
|
170
|
+
- Options: `[Push adesso (git push origin $TRUNK)]` / `[Cherry-pick a parte e continua]` / `[Lascia così e procedi (lo gestisco io)]` / `[Abort]`.
|
|
164
171
|
- **`N\tM`** (diverged both ways) — invoke `AskUserQuestion`:
|
|
165
|
-
- Question: `"Local
|
|
166
|
-
- Options: `[Rebase local
|
|
167
|
-
|
|
168
|
-
The same gate applies if the user-configured trunk branch is something other than `develop` — read `git.trunk_branch` from `baldart.config.yml` if present, default to `develop`.
|
|
172
|
+
- Question: `"Local $TRUNK è diverged da origin/$TRUNK: N behind, M ahead. Servono entrambe le riconciliazioni. Come procedo?"`
|
|
173
|
+
- Options: `[Rebase local $TRUNK su origin/$TRUNK]` / `[Mostrami i commit e fammi decidere]` / `[Abort]`.
|
|
169
174
|
|
|
170
175
|
5. **Log and proceed** — write to the tracker:
|
|
171
176
|
```
|
|
172
177
|
## Phase 0 — Workspace Hygiene Pre-flight
|
|
173
178
|
Status: PASS
|
|
174
179
|
Main repo: $MAIN
|
|
175
|
-
|
|
176
|
-
|
|
180
|
+
Trunk branch: $TRUNK
|
|
181
|
+
Dirty: <none | stashed: <message-label> | user-override>
|
|
182
|
+
Divergence (local…origin/$TRUNK): <0\t0 | resolved: ff-pull | resolved: pushed | user-deferred>
|
|
177
183
|
Completed: <timestamp>
|
|
178
184
|
```
|
|
179
185
|
If any step ended in HALT, set `Status: HALT` and stop — do NOT continue to `## Pre-flight (once)`.
|
|
@@ -205,14 +211,14 @@ Main repo: [/absolute/path/to/main/repo]
|
|
|
205
211
|
|
|
206
212
|
**Decision logic:**
|
|
207
213
|
|
|
208
|
-
1. Read `execution_strategy.recommended_mode` from the epic parent card (if it exists). If present, use it as the default.
|
|
214
|
+
1. Read `execution_strategy.recommended_mode` from the epic parent card (if it exists). If present, use it as the default. The `execution_strategy` block is authored by `prd-card-writer` with the canonical shape `groups:` (a list, each entry has `level:` (int) + `cards:` (list)) — consume that shape, not a flat `parallel_group` field.
|
|
209
215
|
2. If no `execution_strategy` exists, compute:
|
|
210
216
|
- Count total cards in batch
|
|
211
|
-
- Count max cards in any single
|
|
212
|
-
- If
|
|
217
|
+
- Count max cards in any single group (from `execution_strategy.groups[].cards`, i.e. cards sharing the same `level`)
|
|
218
|
+
- If no `execution_strategy.groups` exist, compute the levels on-the-fly: build dependency graph from `depends_on`/`blocks`, add conflict edges for cards sharing `(MODIFY)` files, compute topological layers via BFS — each topological layer becomes one group `level`.
|
|
213
219
|
3. Apply threshold:
|
|
214
|
-
- **Sequential mode** if ANY of: total cards <= 3 — OR all cards are in different
|
|
215
|
-
- **Team mode** if: total cards > 3 AND at least one
|
|
220
|
+
- **Sequential mode** if ANY of: total cards <= 3 — OR all cards are in different groups (max group size = 1, nothing to parallelize) — OR all cards form a linear dependency chain.
|
|
221
|
+
- **Team mode** if: total cards > 3 AND at least one group has 2+ cards.
|
|
216
222
|
4. Log decision in tracker:
|
|
217
223
|
```
|
|
218
224
|
## Execution Mode
|
|
@@ -227,20 +233,20 @@ Main repo: [/absolute/path/to/main/repo]
|
|
|
227
233
|
```
|
|
228
234
|
Proceed without asking (the PRD already approved the strategy).
|
|
229
235
|
|
|
230
|
-
When `mode == sequential`, the per-card pipeline below runs exactly as documented. The `
|
|
236
|
+
When `mode == sequential`, the per-card pipeline below runs exactly as documented. The `execution_strategy.groups` levels are simply ignored. When `mode == team`, skip the per-card pipeline and follow the **Team Mode** section at the end of this document.
|
|
231
237
|
|
|
232
238
|
3d. **Codex batch cross-card grounding check** (runs in background during worktree setup)
|
|
233
239
|
|
|
234
|
-
> **Why**:
|
|
240
|
+
> **Why**: a non-Anthropic frontier model (Codex, via `codex-companion.mjs`) reviews the full card batch for cross-card conflicts that per-card plan-auditor checks cannot detect (each plan-auditor sees only one card).
|
|
235
241
|
|
|
236
242
|
**Skip if**: batch has only 1 card (no cross-card conflicts possible).
|
|
237
243
|
|
|
238
244
|
Launch via `Bash` with `run_in_background: true` and `timeout: 300000`:
|
|
239
245
|
|
|
240
246
|
```bash
|
|
241
|
-
AUDIT_FILE="/tmp/codex-crosscard
|
|
247
|
+
AUDIT_FILE="/tmp/codex-crosscard-<FIRST-CARD-ID>-<SESSION-ID>.md" && \
|
|
242
248
|
CODEX_SCRIPT="$(ls -d ~/.claude/plugins/marketplaces/openai-codex/plugins/codex/scripts/codex-companion.mjs ~/.claude/plugins/cache/openai-codex/codex/*/scripts/codex-companion.mjs 2>/dev/null | sort -V | tail -1)" && \
|
|
243
|
-
[ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" && exit 1; \
|
|
249
|
+
[ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" | tee "$AUDIT_FILE" && exit 1; \
|
|
244
250
|
node "$CODEX_SCRIPT" task --wait "
|
|
245
251
|
Cross-card grounding check for a batch of backlog cards about to be implemented together.
|
|
246
252
|
Your job is to find conflicts BETWEEN cards that per-card reviewers would miss.
|
|
@@ -256,7 +262,7 @@ Main repo: [/absolute/path/to/main/repo]
|
|
|
256
262
|
(e.g., Card A adds field X to interface Foo, Card B restructures Foo entirely)
|
|
257
263
|
2. IMPLICIT DEPENDENCIES: Does Card A change a type/function that Card B's
|
|
258
264
|
requirements assume stays unchanged? Flag missing depends_on.
|
|
259
|
-
3. EXECUTION ORDER RISKS: Given the
|
|
265
|
+
3. EXECUTION ORDER RISKS: Given the execution_strategy group/level assignments, will parallel
|
|
260
266
|
execution cause merge conflicts or type errors?
|
|
261
267
|
4. SHARED STATE MUTATIONS: Do multiple cards write to the same persistence
|
|
262
268
|
{entity} ({collection|table|item} per `stack.database`) in ways that could
|
|
@@ -276,59 +282,61 @@ Main repo: [/absolute/path/to/main/repo]
|
|
|
276
282
|
- `${CARD_PATHS}`: newline-separated list of all `- backlog/FEAT-XXXX-*.yml` paths in the batch
|
|
277
283
|
- `${FILE_OWNERSHIP_MAP}`: the file-ownership map built in step 3b
|
|
278
284
|
|
|
285
|
+
> `<SESSION-ID>` is the current session id (e.g. `$CLAUDE_CODE_SESSION_ID`, or a run UUID if unset). The task-scoped unique name prevents two concurrent `/new` sessions on the same day from clobbering each other's findings (a date-only name silently collides). Record the exact `$AUDIT_FILE` path in the tracker under `## Cross-Card Conflicts (Codex)` so the result-handling step reads the SAME path — never re-derive it by wildcard/timestamp.
|
|
286
|
+
|
|
279
287
|
**Result handling** (read before Phase 1 of first card):
|
|
280
|
-
-
|
|
281
|
-
- If
|
|
288
|
+
- **Background completion barrier (BLOCKING):** record the background task id when you launch it; do NOT read `$AUDIT_FILE` until that task has completed. Because this gate's verdict steers Phase-1 card ordering, the first card MUST NOT start while the check is in flight.
|
|
289
|
+
- **TIMED_OUT branch:** the launch sets `timeout: 300000` (5 min). If the background task hits the timeout without producing a terminal result (the tail of `$AUDIT_FILE` shows no `PASS` / conflict block / `CODEX_NOT_FOUND`), treat it as **TIMED_OUT** — do NOT leave the task "in-progress" and silently proceed. Log `cross-card-check: TIMED_OUT` in `## Cross-Card Conflicts (Codex)` and take the SAME fallback as `CODEX_NOT_FOUND`: spawn `code-reviewer` over the batch with the four conflict questions. Never start the batch with cross-card review in an unresolved/in-flight state.
|
|
290
|
+
- Read the exact `$AUDIT_FILE` path recorded in the tracker after the background command completes.
|
|
291
|
+
- If the file contains **`CODEX_NOT_FOUND`** (Codex unavailable): do NOT silently proceed — **fallback**: spawn the `code-reviewer` agent over the full batch's card YAMLs + file-ownership map with the same cross-card conflict questions (FILE_CONFLICT / IMPLICIT_DEP / ORDER_RISK / STATE_MUTATION). If `code-reviewer` is also unavailable, surface `CAPABILITY_UNAVAILABLE: cross-card-review` to the user and ask whether to proceed without cross-card detection or halt. Never run a multi-card batch with cross-card review silently skipped.
|
|
292
|
+
- If **PASS** or file empty: proceed normally.
|
|
282
293
|
- If **conflicts found**: log in tracker under `## Cross-Card Conflicts (Codex)` and present to user. For each conflict:
|
|
283
294
|
- `FILE_CONFLICT` / `ORDER_RISK` → force the conflicting cards sequential (update file-ownership map).
|
|
284
295
|
- `IMPLICIT_DEP` → add `depends_on` entry to tracker notes (do NOT modify backlog YAML).
|
|
285
296
|
- `STATE_MUTATION` → add warning to both cards' Phase 2 briefings.
|
|
286
297
|
|
|
287
298
|
4. **Worktree setup** — delegate to the **worktree-manager** skill (`/nw` in programmatic mode):
|
|
288
|
-
a.
|
|
289
|
-
b.
|
|
290
|
-
c. The skill
|
|
291
|
-
d.
|
|
292
|
-
e.
|
|
293
|
-
|
|
294
|
-
|
|
299
|
+
a. **Resolve the `slug`** (required by the `/nw` programmatic API — `{ cards, groupParent, slug, branch? }`). Derive it deterministically: if the parent card (or the lead card) has `git_strategy.branch` set, parse the slug from it (`feat/<PARENT-ID>-<slug>` → `<slug>`); otherwise slugify the parent/lead card `title` (lowercase, non-alphanumerics → `-`, collapse repeats, trim, cap ~40 chars). Persist the resolved `slug` in the tracker `## Worktree` section so the path/branch are reproducible across compaction. Do NOT let `/nw` invent its own slug — pass it explicitly.
|
|
300
|
+
b. Pass all card IDs, their `group.parent` fields, AND the resolved `slug` to the skill's grouping logic.
|
|
301
|
+
c. The skill handles: grouping cards by `group.parent`, deriving branch names from `git_strategy.branch` (falling back to `feat/<PARENT-ID>-<slug>` using the slug you passed), creating the worktree in `.worktrees/`, installing dependencies, copying env files, assigning a free port, and verifying the build.
|
|
302
|
+
d. The skill updates `.worktrees/registry.json` with the worktree entry (including all card IDs in the `cards` field).
|
|
303
|
+
e. If build fails → the skill STOPs and reports. Do NOT continue.
|
|
304
|
+
f. Record the worktree path, branch, slug, and port from the skill's output in the tracker.
|
|
305
|
+
5. **Tracker already exists** — the `/tmp/batch-tracker-<FIRST-CARD-ID>.md` file was created at batch start (before Phase 0, see "Context Tracking"). Here, backfill the `## Worktree` section with the worktree path, branch, slug, and port resolved in step 4, AND write `Created: <ISO-8601 now>` (`date -u +%Y-%m-%dT%H:%M:%SZ`) — this is the strategy-independent start anchor Phase 8's `cycle_time_mins` reads. Do NOT re-create the file (Phase 0 has already written to it).
|
|
306
|
+
6. Create a task list to track progress across all cards.
|
|
295
307
|
|
|
296
308
|
---
|
|
297
309
|
|
|
298
310
|
## QA Profile Selector
|
|
299
311
|
|
|
300
|
-
Before Phase 3.5, determine the review profile for each card.
|
|
312
|
+
Before Phase 3.5, determine the review profile for each card. **`/new` is a CONSUMER of `review_profile`, not the place where the decision criteria live.**
|
|
301
313
|
|
|
302
314
|
**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
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
>
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
| **BALANCED** | Default for ALL `feature` / `enhancement` cards not matching DEEP rules — OR `bugfix`/`refactor` with >3 files or HIGH-risk keywords |
|
|
321
|
-
| **DEEP** | ANY of: areas includes both `api` + `data` — OR paths/title contain `auth`, `payment`, `permission`, `schema`, `migration`, `cron`, `webhook`, `transaction` — OR >15 files likely touched — OR acceptance criteria count > 5 — OR DB indexes changed (`db_indexes` block present, or legacy `firestore_indexes`) — OR API contract changed — OR `data_fields` block has ≥3 entries with `status: new` or `status: modified` |
|
|
322
|
-
|
|
323
|
-
**Critical**: `feature` and `enhancement` cards are ALWAYS BALANCED minimum — never LIGHT. The `files_likely_touched` field in YAML underestimates actual scope; ignore it for profile decisions on feature cards. When in doubt between BALANCED and DEEP, use DEEP.
|
|
315
|
+
The PRD `prd-card-writer` computes this field at authoring time — the decision criteria
|
|
316
|
+
(how `skip`/`light`/`balanced`/`deep` is chosen, including the `>15-file → deep` trigger and
|
|
317
|
+
the `feature`/`enhancement` ≥ balanced floor) are the **SSOT in `prd-card-writer.md § Rule C`**.
|
|
318
|
+
They are deliberately NOT reproduced here. If the card has a `review_profile` ∈ {`skip`,
|
|
319
|
+
`light`, `balanced`, `deep`}, **use it verbatim** — do NOT recompute. Log `profile=<x> (from card)`
|
|
320
|
+
in the tracker.
|
|
321
|
+
|
|
322
|
+
**Fallback path (legacy cards only — no `review_profile` field):** cards authored before v3.38.0
|
|
323
|
+
(or manually) lack the field. Only then, compute the profile by reading the decision criteria
|
|
324
|
+
from the SSOT: **`review_profile` is computed by prd-card-writer (Rule C); see
|
|
325
|
+
`framework/.claude/agents/prd-card-writer.md` for the criteria.** Apply those criteria here,
|
|
326
|
+
then log `profile=<x> (computed — review_profile absent)`. There is no second copy of the
|
|
327
|
+
criteria in this file — keeping one authority avoids the drift that previously let the two tables
|
|
328
|
+
disagree.
|
|
329
|
+
|
|
330
|
+
> Note: the qa-sentinel agent keeps its OWN, different mapping (`profile → SCOPED/FULL` test tier),
|
|
331
|
+
> which is legitimately qa-sentinel's; that is not the same thing as this profile-selection criteria.
|
|
324
332
|
|
|
325
333
|
---
|
|
326
334
|
|
|
327
335
|
## Agent Routing (Phase 2 dispatcher)
|
|
328
336
|
|
|
329
337
|
Phase 2 reads the card's `owner_agent` field and dispatches to the matching
|
|
330
|
-
specialist. The enum
|
|
331
|
-
|
|
338
|
+
specialist. The enum's single source of truth is the **`owner_agent enum` block in
|
|
339
|
+
`framework/.claude/agents/REGISTRY.md`** (applied by `prd-card-writer.md § Agent
|
|
332
340
|
Specialization Rules`) and validated by the PRD validation phase
|
|
333
341
|
(`framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0).
|
|
334
342
|
|
|
@@ -339,15 +347,21 @@ Specialization Rules`) and validated by the PRD validation phase
|
|
|
339
347
|
| `plan` | Fallback to `coder` + WARN | Standard coder briefing + log `"[ROUTER] plan-only briefing not yet implemented — using coder"` |
|
|
340
348
|
| `visual-designer` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
|
|
341
349
|
| `motion-expert` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
|
|
342
|
-
| missing / `
|
|
350
|
+
| missing / `""` / `claude` (legacy placeholders only) | Fallback to `coder` + WARN | Standard coder briefing + log `"[ROUTER] card <ID> has no valid owner_agent (got '<raw>'); defaulting to coder"` |
|
|
351
|
+
| any other unrecognized value (typo, unregistered agent) | **HALT + ask the user** | No briefing — the router stops and surfaces the literal value (see pseudocode step 6b) |
|
|
343
352
|
|
|
344
353
|
The three `plan` / `visual-designer` / `motion-expert` stubs exist so the
|
|
345
354
|
router never blocks a card; specialized briefings are tracked as a follow-up.
|
|
355
|
+
**Only the empty/missing/`claude` legacy placeholders fall back to `coder`** — a
|
|
356
|
+
genuinely unrecognized value (e.g. a typo `coder-agent`, or an agent not in the
|
|
357
|
+
enum) HALTs so a mis-routed card is never silently downgraded. The table and the
|
|
358
|
+
step-6b pseudocode are the same contract stated twice; keep them in lockstep.
|
|
346
359
|
|
|
347
|
-
|
|
360
|
+
The valid values come from ONE place — `REGISTRY.md`'s `owner_agent enum` block. Do not
|
|
361
|
+
re-list them here or maintain parallel copies; if the roster changes, edit the enum in
|
|
362
|
+
`REGISTRY.md` and these consumers read it:
|
|
348
363
|
|
|
349
|
-
- `framework/.claude/
|
|
350
|
-
- `framework/.claude/skills/prd/assets/card-template.yml` (the placeholder),
|
|
364
|
+
- `framework/.claude/skills/prd/assets/card-template.yml` (the placeholder cites the REGISTRY enum),
|
|
351
365
|
- `framework/.claude/agents/prd-card-writer.md § Agent Specialization Rules`,
|
|
352
366
|
- `framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0a,
|
|
353
367
|
- `framework/.claude/agents/REGISTRY.md` decision-tree.
|
|
@@ -362,16 +376,19 @@ For each card, execute these phases in order:
|
|
|
362
376
|
|
|
363
377
|
### Phase 1 — Claim & Context
|
|
364
378
|
1. **Update tracker**: set current card, phase = "1-claim".
|
|
365
|
-
2.
|
|
366
|
-
2b. **`depends_on` gate** — read the card's `depends_on` field. For each listed card ID:
|
|
379
|
+
2. **`depends_on` gate (BEFORE claiming)** — read the card's `depends_on` field. For each listed card ID:
|
|
367
380
|
- Read that card's backlog YAML and check its `status` field.
|
|
368
|
-
- If NOT `DONE` → HALT: log in `## Issues & Flags` and ask the user: "Card <CARD-ID> depends on <DEP-ID> which is `<status>`. Proceed anyway, or wait?" Do not start implementation until the user responds explicitly.
|
|
369
|
-
- If `DONE` → continue.
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
381
|
+
- If NOT `DONE` → HALT: log in `## Issues & Flags` and ask the user: "Card <CARD-ID> depends on <DEP-ID> which is `<status>`. Proceed anyway, or wait?" Do not start implementation until the user responds explicitly. **The card status is NOT written until this gate passes** — so a HALT leaves the card untouched (no stale `IN_PROGRESS` for the next run to mis-read).
|
|
382
|
+
- If `DONE` (or the user chose "proceed anyway") → continue.
|
|
383
|
+
2b. **Claim** — only now set the card status to `IN_PROGRESS` and assign yourself.
|
|
384
|
+
3. Invoke the **codebase-architect** agent (MUST per AGENTS.md) to understand the relevant codebase area, existing patterns, and architecture before any implementation. When `features.has_lsp_layer: true`, the architect uses LSP find-references for identifier-shaped lookups — this needs NO handoff from the orchestrator: the architect reads `features.has_lsp_layer` from `baldart.config.yml` directly (the flag is ambient) per `agents/code-search-protocol.md`. The orchestrator does NOT propagate the flag. (Earlier doc versions numbered this step 4; the step that read project-status BEFORE the architect was removed because it persisted pre-analysis context — see step 3a.)
|
|
385
|
+
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.
|
|
386
|
+
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):
|
|
387
|
+
```
|
|
388
|
+
mode: QUICK
|
|
389
|
+
Grounding check only (NOT a full audit — do not run the full AUDIT CHECKLIST A-H, and do not
|
|
390
|
+
re-invoke codebase-architect; the findings are pasted below). Verify this backlog card's
|
|
391
|
+
requirements are grounded in the actual codebase.
|
|
375
392
|
|
|
376
393
|
Check:
|
|
377
394
|
1. Do all paths in files_likely_touched actually exist?
|
|
@@ -383,14 +400,14 @@ For each card, execute these phases in order:
|
|
|
383
400
|
[paste full card YAML]
|
|
384
401
|
|
|
385
402
|
Codebase-architect findings:
|
|
386
|
-
[paste key findings from step
|
|
403
|
+
[paste key findings from step 3]
|
|
387
404
|
|
|
388
405
|
Return: PASS | FIXES NEEDED (list exact corrections). No full audit report needed.
|
|
389
406
|
```
|
|
390
407
|
- If **FIXES NEEDED**: apply corrections to the tracker notes for this card (do NOT modify the backlog YAML). Carry the corrected requirements into the Phase 2 briefing.
|
|
391
408
|
- If **PASS**: proceed.
|
|
392
409
|
5. **Update tracker**: phase = "1-claim DONE", log codebase-architect key findings (1-2 lines) and plan-auditor result (PASS or corrections applied).
|
|
393
|
-
5b. **Persist the architecture baseline for reuse (since v3.35.0)** — write the
|
|
410
|
+
5b. **Persist the architecture baseline for reuse (since v3.35.0)** — write the **untruncated codebase-architect task result verbatim** (the full Task-tool output: file paths, type signatures, patterns, high-risk paths) to `/tmp/arch-baseline-<CARD-ID>.md`. This is NOT the 1-2-line tracker summary from step 5 — serialize the agent's complete output to disk BEFORE you summarize it for the tracker, so Phase 3.7's per-card `/codexreview` (lean mode, reuses this file instead of re-spawning `codebase-architect`) gets enough detail to ground a reviewer. If you summarize first and write the summary, the lean contract is defeated.
|
|
394
411
|
|
|
395
412
|
### Phase 2 — Implement (self-healing, up to 3 retries)
|
|
396
413
|
6. **Update tracker**: phase = "2-implement".
|
|
@@ -398,6 +415,10 @@ For each card, execute these phases in order:
|
|
|
398
415
|
|
|
399
416
|
```
|
|
400
417
|
Let raw = card.owner_agent (string, may be missing).
|
|
418
|
+
# Epic guard FIRST — an epic is a tracker, not implementable work.
|
|
419
|
+
If card is an epic (id ends "-00" OR filename ends "-epic.yml" OR review_profile == "skip"
|
|
420
|
+
with no requirements): SKIP — do NOT dispatch to any agent. Log
|
|
421
|
+
"[ROUTER] card <ID> is an epic (tracker) — skipped, not implemented" and move to the next card.
|
|
401
422
|
Switch on raw:
|
|
402
423
|
- "coder" → spawn = "coder", briefing = "coder"
|
|
403
424
|
- "ui-expert" → spawn = "ui-expert", briefing = "ui-expert"
|
|
@@ -422,7 +443,7 @@ For each card, execute these phases in order:
|
|
|
422
443
|
|
|
423
444
|
### Card Specification (verbatim — do not paraphrase)
|
|
424
445
|
Requirements:
|
|
425
|
-
[copy full requirements list from card YAML, including any corrections from plan-auditor step
|
|
446
|
+
[copy full requirements list from card YAML, including any corrections from the plan-auditor grounding check (step 4)]
|
|
426
447
|
|
|
427
448
|
Acceptance Criteria:
|
|
428
449
|
[copy full acceptance_criteria list from card YAML]
|
|
@@ -571,9 +592,8 @@ For each card, execute these phases in order:
|
|
|
571
592
|
### Project Anti-Patterns & NFRs (ENFORCED)
|
|
572
593
|
Violating these is a BLOCKER in code review.
|
|
573
594
|
|
|
574
|
-
Deprecated patterns
|
|
575
|
-
|
|
576
|
-
- Example: deprecated permission shortcuts, deprecated client-state APIs, etc.
|
|
595
|
+
Deprecated patterns — the orchestrator MUST fill this from the project's own AGENTS.md / MEMORY.md / coding-standards.md before sending the briefing. If the project documents none, write "None documented." Do NOT pass placeholder example text to the coder (it wastes tokens and confuses the agent):
|
|
596
|
+
[resolved list of this project's deprecated/anti-patterns, or "None documented."]
|
|
577
597
|
|
|
578
598
|
Performance MUST rules (adapt to your stack):
|
|
579
599
|
- Bounded reads on every database query (`.limit()` / equivalent)
|
|
@@ -637,15 +657,15 @@ For each card, execute these phases in order:
|
|
|
637
657
|
requirements:
|
|
638
658
|
- id: 1
|
|
639
659
|
text: "[verbatim requirement text]"
|
|
640
|
-
status: done |
|
|
660
|
+
status: done | not_implemented
|
|
641
661
|
evidence: "src/path/to/file.ts:LINE_NUMBER"
|
|
642
|
-
notes: "[if
|
|
662
|
+
notes: "[if not_implemented: explain why]"
|
|
643
663
|
- id: 2
|
|
644
664
|
[repeat for each requirement]
|
|
645
665
|
acceptance_criteria:
|
|
646
666
|
- id: 1
|
|
647
667
|
text: "[verbatim criterion text]"
|
|
648
|
-
status: done |
|
|
668
|
+
status: done | not_implemented
|
|
649
669
|
evidence: "src/path/to/file.ts:LINE_NUMBER"
|
|
650
670
|
items_total: [N]
|
|
651
671
|
items_done: [M]
|
|
@@ -657,31 +677,39 @@ For each card, execute these phases in order:
|
|
|
657
677
|
notes: "[if B-missing: exact TODO location and text left; otherwise omit]"
|
|
658
678
|
```
|
|
659
679
|
|
|
680
|
+
Per-requirement / per-AC `status` is BINARY: `done` or `not_implemented` (the legacy
|
|
681
|
+
`partial`/`blocked` values are removed — see `coder.md`). The orchestrator re-derives the
|
|
682
|
+
finer Done/Partial/Missing classification itself in Phase 2.5 by reading the code; the coder
|
|
683
|
+
report is a starting signal, not ground truth.
|
|
660
684
|
If `items_skipped` is not "none", you MUST explain why each was skipped.
|
|
661
|
-
The orchestrator treats any skipped item as a gap requiring a fix agent.
|
|
685
|
+
The orchestrator treats any `not_implemented` or skipped item as a gap requiring a fix agent.
|
|
662
686
|
`conditional_items` MUST list every binary-outcome item from the card. If the card has no
|
|
663
687
|
conditional requirements, omit the field. `branch_taken: B-missing` MUST have a `notes`
|
|
664
688
|
field with the exact file path and line where the TODO comment was written.
|
|
665
689
|
```
|
|
666
690
|
|
|
667
|
-
8. Run
|
|
668
|
-
9. **If any check fails**: categorize the error (`lint | TypeScript | test | build`), log it in the tracker as `retry-cause: <category>`.
|
|
669
|
-
**Stash recovery (MUST check before rewriting)**: before spawning a fix agent or rewriting code, check if a previous stash contains the needed changes:
|
|
691
|
+
8. **Run the verification gates and CAPTURE their output** (so step 9 can pass it to a fix agent). Each is its own gate:
|
|
670
692
|
```bash
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
693
|
+
cd <worktree-path>
|
|
694
|
+
npm run lint 2>&1 | tee /tmp/lint-<CARD-ID>.txt
|
|
695
|
+
# tsc is its OWN blocking gate — run it ONLY when stack.language includes "typescript"
|
|
696
|
+
# (do NOT assume `npm run build` covers tsc — Next.js dev builds and many setups skip it):
|
|
697
|
+
npx tsc --noEmit 2>&1 | tee /tmp/tsc-<CARD-ID>.txt # guard: when stack.language includes "typescript"
|
|
698
|
+
npm test 2>&1 | tee /tmp/test-<CARD-ID>.txt # if tests exist
|
|
699
|
+
npm run build 2>&1 | tee /tmp/build-<CARD-ID>.txt
|
|
700
|
+
```
|
|
701
|
+
When `stack.language` does NOT include `typescript`, skip the `tsc` line (no equivalent gate). Capturing to `/tmp/*-<CARD-ID>.txt` guarantees the failing output is available for step 9 — do NOT run the gates without capture.
|
|
702
|
+
9. **If any check fails**: categorize the error (`lint | TypeScript | test | build`), log it in the tracker as `retry-cause: <category>`.
|
|
703
|
+
**Code-recovery check (MUST do before rewriting)**: before spawning a fix agent or rewriting code, check whether lint-staged or a pre-commit hook removed code that is actually needed (e.g. a field "unused" at commit time but consumed by later code). Inspect the captured diff and `git diff`/`git log -p` for the worktree branch and restore the needed code by an explicit file write. **Do NOT `git stash pop` inside the worktree** — `refs/stash` is globally shared across worktrees (`$GIT_COMMON_DIR`), so a stash created or popped in a worktree can corrupt another worktree's state (see Phase 4 WORKTREE COMMIT RULE). If you need to set work aside in a worktree, make a clearly-labelled WIP commit and record its hash in the tracker for later squash, never a stash.
|
|
704
|
+
When spawning a fix agent: scope it exclusively to this card's Edit-allowed files (from `## File Ownership Map`) — it MUST NOT touch files owned by other cards. Pass the fix agent: the error output (from the captured `/tmp/*-<CARD-ID>.txt` files), the error category, the explicit list of files it may edit, and the failing check output. Do NOT ask the user — just fix and re-run. Fix the code, not the tests (unless the test itself is wrong). Repeat up to **3 times**. **Stuck-loop guard**: compare the failing error's fingerprint (file:line + message) between retries; if the SAME error reproduces on 2 consecutive retries, the fix is not converging (often a constraint outside the card's ownership map) — stop early, log `[STUCK-LOOP] <error>` in `## Issues & Flags`, and escalate to the user rather than burning the 3rd retry on an identical failure.
|
|
705
|
+
10. If still failing after 3 retries (or on a stuck loop), log the failure in `## Issues & Flags` and ask the user before continuing.
|
|
680
706
|
11. **Update tracker**: phase = "2-implement DONE", log files changed (short list), retry count, retry causes (e.g., `"2 retries: TypeScript x1, lint x1"`), and test results (new + existing test count, pass/fail).
|
|
681
|
-
11b. **File diff gate** — verify the coder only touched its allowed files:
|
|
707
|
+
11b. **File diff gate** — verify the coder only touched its allowed files. The coder commits its work (per `coder.md`), so a bare `git diff --name-only HEAD` is vacuous (clean tree). Detect what the card's commits actually changed against the trunk, with an uncommitted-fallback:
|
|
682
708
|
```bash
|
|
683
|
-
cd <worktree-path>
|
|
709
|
+
cd <worktree-path>
|
|
710
|
+
git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD
|
|
684
711
|
```
|
|
712
|
+
(`$TRUNK` is the trunk branch resolved in Phase 0; if the worktree branched from a different base, the `HEAD~1..HEAD` fallback covers the last commit.)
|
|
685
713
|
Compare against this card's allowed files in `## File Ownership Map`.
|
|
686
714
|
- **All within allowed set** → proceed to Phase 2.5.
|
|
687
715
|
- **Any file outside allowed set** → log the violation in `## Issues & Flags` (`"unauthorized file: <path>"`), then spawn a **targeted revert coder agent** with instruction: "Revert ONLY these files to their pre-commit state. Do not touch any other file: [list unauthorized files]". Re-run build + lint to confirm clean state after revert. Update tracker with revert outcome, then proceed to Phase 2.5.
|
|
@@ -705,6 +733,10 @@ Before triggering any review, you MUST verify that the coder agent implemented *
|
|
|
705
733
|
|
|
706
734
|
If NEITHER branch artifact exists → classify as `Missing` (not Partial) and trigger the
|
|
707
735
|
gap-resolution fix agent sub-loop immediately for these items (before continuing the checklist).
|
|
736
|
+
**Loop-counter scope**: the max-2 gap-resolution cap is tracked PER ITEM, not per phase. The
|
|
737
|
+
step-0 pre-scan and the step-5 main loop share the same per-item budget — an item that consumed
|
|
738
|
+
both retries here is NOT given two fresh retries at step 5; an item never touched here keeps its
|
|
739
|
+
full budget at step 5. This prevents both over-fixing (4 spawns) and starvation (0 retries left).
|
|
708
740
|
|
|
709
741
|
Also check: if the card has conditional requirements but the completion report has no
|
|
710
742
|
`conditional_items` section → flag as `Missing` (the coder must document the branch taken).
|
|
@@ -794,15 +826,17 @@ Before triggering any review, you MUST verify that the coder agent implemented *
|
|
|
794
826
|
- The exact list of unimplemented items (copy the checklist rows)
|
|
795
827
|
- The file-ownership restrictions from `## File Ownership Map`
|
|
796
828
|
- The instruction: "Implement ONLY these missing items. Do not refactor or expand scope."
|
|
797
|
-
- After the fix agent completes, re-run
|
|
829
|
+
- After the fix agent completes, re-run the static gates the fix could have broken — `npm run lint`, `npx tsc --noEmit` (when `stack.language` includes typescript), and `npm test` — not just build + lint (a gap-fix can introduce a type error or break a test that the earlier Phase 2 gate had passed).
|
|
798
830
|
- Re-verify each fixed item against the code — do NOT trust the agent's self-report.
|
|
799
|
-
- Repeat this sub-loop up to **2 times
|
|
831
|
+
- Repeat this sub-loop up to **2 times** (per-item budget, shared with step 0 — see "Loop-counter scope"). After 2 loops, if items remain Partial or Missing:
|
|
800
832
|
- Log in `## Issues & Flags`: list each unimplemented requirement.
|
|
801
833
|
- Ask the user whether to proceed to review despite the gap or stop.
|
|
834
|
+
- **Handoff to Phase 2.5b**: any AC that is still `Partial` or `Missing` at this point (whether the user said "proceed" or not) MUST be seeded into the Phase 2.5b AC Closure Ledger as a `deferred` row with `User-approved? pending` — the user's "proceed to review" answer here does NOT auto-approve the deferral; Phase 2.5b Step 4 still asks per-AC. Do NOT let "proceed" silently mark these ACs `implemented`.
|
|
802
835
|
|
|
803
|
-
5b. **API contract check
|
|
804
|
-
- From `git diff --name-only`, identify `route.ts` files that existed before this card.
|
|
805
|
-
-
|
|
836
|
+
5b. **API contract check**:
|
|
837
|
+
- From `git diff --name-only "$TRUNK...HEAD"`, identify `route.ts` files that existed before this card (MODIFIED) vs newly added (NEW).
|
|
838
|
+
- **NEW routes** are exempt from the breaking-change comparison (no prior contract to violate) BUT must still be checked for a **path collision**: read `${paths.references_dir}/api/index.md` and confirm the new route's URL path is not already documented under a different module. A collision → `[API-CONTRACT] PATH-COLLISION` in `## Issues & Flags` (BLOCKER — a second handler for a documented path).
|
|
839
|
+
- For each MODIFIED route:
|
|
806
840
|
a. Derive the API module from path (e.g., `src/app/api/v1/booking/[id]/route.ts` → `booking`).
|
|
807
841
|
b. Read `${paths.references_dir}/api/<module>.md` (or subdirectory match).
|
|
808
842
|
c. Read the modified route, extract response shape from `NextResponse.json()` calls.
|
|
@@ -811,10 +845,10 @@ Before triggering any review, you MUST verify that the coder agent implemented *
|
|
|
811
845
|
Added fields only → `[API-CONTRACT] ADDITIVE` (informational).
|
|
812
846
|
No doc found → `[API-CONTRACT] NO-DOC` (informational).
|
|
813
847
|
|
|
814
|
-
5c. **Reference-aliasing mutation check** (MANDATORY — deterministic detector,
|
|
848
|
+
5c. **Reference-aliasing mutation check** (MANDATORY — deterministic detector, reference-aliasing mutation prevention).
|
|
815
849
|
|
|
816
850
|
Detect call sites that pair a helper invocation with in-place mutation of an input array
|
|
817
|
-
without an identity guard. Anti-pattern (the
|
|
851
|
+
without an identity guard. Anti-pattern (the reference-aliasing mutation family):
|
|
818
852
|
|
|
819
853
|
```ts
|
|
820
854
|
const result = filterHelper(input, ...);
|
|
@@ -822,12 +856,14 @@ input.length = 0; // ← wipes both input AND result when result === in
|
|
|
822
856
|
input.push(...result); // ← pushes zero elements (result was just emptied)
|
|
823
857
|
```
|
|
824
858
|
|
|
825
|
-
|
|
859
|
+
This detector targets TypeScript/JavaScript array-mutation patterns. **Guard: run it only when `stack.language` includes `typescript` or `javascript`.** For other languages it does not apply — log `[ALIAS-MUTATION] skipped — stack.language not ts/js` and continue (do NOT report a non-TS diff as "clean", which would imply the check ran).
|
|
860
|
+
|
|
861
|
+
Run this exact bash block in the worktree (`$TRUNK` = the trunk branch resolved in Phase 0):
|
|
826
862
|
|
|
827
863
|
```bash
|
|
828
864
|
cd <worktree-path>
|
|
829
|
-
CHANGED_TS="$(git diff --name-only
|
|
830
|
-
|| git diff --name-only HEAD~1 -- '*.ts' '*.tsx')"
|
|
865
|
+
CHANGED_TS="$(git diff --name-only "$TRUNK...HEAD" -- '*.ts' '*.tsx' '*.js' '*.jsx' 2>/dev/null \
|
|
866
|
+
|| git diff --name-only HEAD~1..HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx')"
|
|
831
867
|
|
|
832
868
|
ALIAS_HITS=()
|
|
833
869
|
for f in $CHANGED_TS; do
|
|
@@ -862,27 +898,27 @@ For each hit, classify by reading 10 lines of context around the match:
|
|
|
862
898
|
|
|
863
899
|
For each `[ALIAS-MUTATION] BLOCKER`:
|
|
864
900
|
|
|
865
|
-
- Spawn a targeted fix `coder` agent with the exact file:line and instruction: "Add identity guard `if (result !== input) { ... }` around the in-place reset, OR clone the input with `[...input]` before passing it to the helper. Add a regression test on the caller pattern
|
|
901
|
+
- Spawn a targeted fix `coder` agent with the exact file:line and instruction: "Add identity guard `if (result !== input) { ... }` around the in-place reset, OR clone the input with `[...input]` before passing it to the helper. Add a regression test on the caller pattern, co-located with the helper's existing tests following this project's test convention (e.g. a `*-reference` negative-control test next to the helper's test file). Read `agents/coding-standards.md § Reference-Aliasing Mutation Patterns` before implementing."
|
|
866
902
|
- Re-run the detector after the fix. The hit MUST classify as Guarded, Cloned, or helper-immutable. Repeat **max 2 times**.
|
|
867
903
|
- If still un-guarded after 2 loops → log in `## Issues & Flags` and ask the user.
|
|
868
904
|
|
|
869
|
-
Rationale
|
|
905
|
+
Rationale (reference-aliasing incident class): a helper that returns its same input reference on some code paths, combined with a call site that did `arr.length = 0; arr.push(...result)` without an identity guard, silently wiped the result. The helper passed unit tests in isolation; the bug only manifested end-to-end. This detector closes that detection gap. Full policy: `agents/coding-standards.md § Reference-Aliasing Mutation Patterns`.
|
|
870
906
|
|
|
871
907
|
5d. **Caller-pattern test coverage check** (MANDATORY — when card introduces or modifies an exported helper consumed by 1+ caller with in-place mutation).
|
|
872
908
|
|
|
873
|
-
If the card's diff includes BOTH (a) an `export function` / `export const` declaration in a `
|
|
909
|
+
If the card's diff includes BOTH (a) an `export function` / `export const` declaration in a shared-library file (under `${paths.lib}` if defined, else the project's lib/util dir) AND (b) at least one call site in another file that mutates an input array in place (detected via the bash block in 5c), verify that a test file exists that exercises the **caller pattern** — not only the helper in isolation.
|
|
874
910
|
|
|
875
911
|
Required test characteristics:
|
|
876
912
|
|
|
877
|
-
- At least one case asserts the post-call state of the input array (e.g. `assert.strictEqual(
|
|
878
|
-
- At least one **negative-control case** documents the failure mode that would occur if the identity guard / defensive clone were removed
|
|
913
|
+
- At least one case asserts the post-call state of the input array (e.g. `assert.strictEqual(arr.length, N)` after the helper invocation).
|
|
914
|
+
- At least one **negative-control case** documents the failure mode that would occur if the identity guard / defensive clone were removed.
|
|
879
915
|
|
|
880
916
|
If the test is missing:
|
|
881
917
|
|
|
882
|
-
- Spawn a targeted fix `coder` agent to write the test. The test MUST live in a file co-located with similar helpers (
|
|
883
|
-
- This is BLOCKING for Phase 4 commit when the helper is on a high-risk path (auth
|
|
918
|
+
- Spawn a targeted fix `coder` agent to write the test. The test MUST live in a file co-located with similar helpers, following this project's test convention (do NOT invent a directory — mirror where the helper's existing tests live).
|
|
919
|
+
- This is BLOCKING for Phase 4 commit when the helper is on a high-risk path (a path listed in `paths.high_risk_modules` in `baldart.config.yml`, e.g. auth / payments / a shared scoring-or-ranking primitive). On non-high-risk paths it's a HIGH-severity flag but the orchestrator may proceed and defer to `/codexreview`.
|
|
884
920
|
|
|
885
|
-
Rationale:
|
|
921
|
+
Rationale: in the originating incident, the helper's caller pattern was never tested (tests were deferred to a later E2E card); the helper passed in isolation while the caller-side aliasing bug shipped. A caller-pattern test at the helper-card level catches this class earlier.
|
|
886
922
|
|
|
887
923
|
6. **Update tracker**: phase = "2.5-completeness DONE", log result (PASS / GAPS REMAIN + count).
|
|
888
924
|
|
|
@@ -921,9 +957,9 @@ This gate enforces `framework/agents/workflows.md § Scope Closure Discipline` a
|
|
|
921
957
|
For each `deferred` row whose `User-approved?` is `pending`, invoke `AskUserQuestion` with:
|
|
922
958
|
- Question: `"AC-<N> of <CARD-ID> non implementata. Testo verbatim: '<AC text>'. Motivazione dell'implementer: '<reason or 'nessuna — silent skip'>'. Come procedo?"`
|
|
923
959
|
- Options (max 4):
|
|
924
|
-
1. **"Implementa adesso"** — spawn a targeted fix `coder` agent scoped to this card's MAY EDIT files (from `## File Ownership Map`) with the instruction "Implement ONLY AC-<N>: '<AC text>'. Do not refactor or expand scope." Re-run Phase 2.5 verification on the resulting diff.
|
|
960
|
+
1. **"Implementa adesso"** — spawn a targeted fix `coder` agent scoped to this card's MAY EDIT files (from `## File Ownership Map`) with the instruction "Implement ONLY AC-<N>: '<AC text>'. Do not refactor or expand scope." Re-run Phase 2.5 verification on the resulting diff — **including the mandatory sub-steps 5b (API contract), 5c (alias-mutation), 5d (caller-pattern test)** if the fix touched a route, an exported helper, or a call site (a single-AC fix can still introduce these). **Hard cap: 2 attempts on the same AC.** On the 2nd failure, do NOT re-offer "Implementa adesso" — re-invoke `AskUserQuestion` with only options 2/3/4 (approve deferral / follow-up card / stop), so the loop cannot recur unbounded.
|
|
925
961
|
2. **"Approva il deferral"** — record `[USER-APPROVED DEFERRAL] <today>: <user-supplied reason>` on its own line in the card's `implementation_notes`. Mark the row `User-approved? yes`.
|
|
926
|
-
3. **"Sposta su follow-up card"** — create a backlog stub at `${paths.backlog_dir}/<CARD-ID>-followup-AC<N>.yml` with the
|
|
962
|
+
3. **"Sposta su follow-up card"** — create a backlog stub at `${paths.backlog_dir}/<CARD-ID>-followup-AC<N>.yml` with `status: TODO` AND the minimum fields the Pre-flight gate (step 1b) requires, so a future `/new` run can pick it up without halting: a non-empty `requirements` (≥1, derived from the AC), a non-empty `acceptance_criteria` (≥1, the verbatim AC text), and a non-empty `files_likely_touched` (≥1, carried from the parent card's ownership map for this AC). Mark the row `User-approved? yes (follow-up: <new-card-id>)`. Do NOT proceed to Phase 2.55 until the follow-up file exists on disk and passes the step-1b field check.
|
|
927
963
|
4. **"Ferma il batch"** — halt the orchestrator, leave the worktree intact, log the reason in `## Issues & Flags`. Do NOT commit.
|
|
928
964
|
|
|
929
965
|
Do NOT batch the question across multiple ACs — one `AskUserQuestion` per AC, so the user sees each AC's text in isolation. Issue the questions sequentially.
|
|
@@ -935,9 +971,9 @@ This gate enforces `framework/agents/workflows.md § Scope Closure Discipline` a
|
|
|
935
971
|
- `covered by` / `already handles` / `redundant`
|
|
936
972
|
- `skipped` / `dropped`
|
|
937
973
|
|
|
938
|
-
|
|
974
|
+
When scanning a line, FIRST check for the `[USER-APPROVED DEFERRAL]` prefix; if present AND the corresponding AC row has `User-approved? yes`, the line is RESOLVED — do NOT re-match the rationalization keywords inside the user-supplied reason text (otherwise a freeform reason like "approve deferral: existing component already handles this" would re-flag an already-approved AC). Only lines WITHOUT the prefix (or whose AC row is not `yes`) are silent deferrals that escaped Step 4 — for those, trigger the Step 4 `AskUserQuestion` for the AC referenced (or for "the unspecified AC implied by this note" if no AC is named, asking the user to clarify which AC the note refers to). **If Step 5 triggers any new Step 4 question, fully resolve it (loop back into Step 4) BEFORE running Step 6** — do NOT write `2.5b-ac-closure DONE` while a triggered question is still open.
|
|
939
975
|
|
|
940
|
-
6. **Update tracker
|
|
976
|
+
6. **Update tracker** (only after Steps 3–5 have fully settled, including any Step-5-triggered Step-4 question): phase = "2.5b-ac-closure DONE". Persist the AC Closure Ledger AND the Rationalization Verification (if any) in the tracker. Log counts on one line:
|
|
941
977
|
|
|
942
978
|
```
|
|
943
979
|
ac-closure: implemented=N | user-approved deferrals=M | follow-up cards created=K | rationalization-verifications passed=L
|
|
@@ -982,13 +1018,13 @@ Every fix-application decision in Phases 2.55 / 3 / 3.5 / 3.7 appends one row to
|
|
|
982
1018
|
|
|
983
1019
|
Some fix domains are **never** safe for inline orchestrator apply, regardless of size — the orchestrator MUST delegate every fix in these domains to the **domain-owning agent**, even when the patch is a one-liner. The owning agent is the one whose system prompt + project overlay encodes that domain's invariants; an orchestrator inline edit (or a fix routed to the wrong agent) routinely breaks them.
|
|
984
1020
|
|
|
985
|
-
Enumerated
|
|
1021
|
+
Enumerated exhaustively:
|
|
986
1022
|
|
|
987
1023
|
| Domain | Owning agent | Match rule |
|
|
988
1024
|
|---|---|---|
|
|
989
1025
|
| `doc` | **`doc-reviewer`** (write mode) | File path matching `*.md` under `${paths.references_dir}`, `${paths.prd_dir}`, project root `CHANGELOG.md`, or any `ssot-registry.md`. |
|
|
990
|
-
| `security` | `coder` | File path matching
|
|
991
|
-
| `migration` | `coder` | File path matching
|
|
1026
|
+
| `security` | `coder` | File path matching any entry in `paths.high_risk_modules` (`baldart.config.yml`) — the same auth/permission/payment-class paths the Phase 3.7 Step A detector reads. Also any SQL migration whose content matches `CREATE POLICY|ALTER POLICY|DROP POLICY` (RLS policy mutations). If `paths.high_risk_modules` is absent, the security match rule emits a one-line diagnostic and matches nothing (no hardcoded default). |
|
|
1027
|
+
| `migration` | `coder` | File path matching `${paths.migrations_dir}/*.sql` if `paths.migrations_dir` is defined in `baldart.config.yml`; otherwise the project's migrations dir per convention (`migrations/`, `db/migrate/`, `supabase/migrations/`, `prisma/migrations/`). |
|
|
992
1028
|
|
|
993
1029
|
**Why `doc` is owned by `doc-reviewer`, not `coder` (since v3.40.0)** — the doc invariants the orchestrator must not break (freshness markers, linking protocol, frontmatter standard, tabular formatting, SSOT/registry coverage, dependency-topological order, SCIP/code refs) are encoded in the **`doc-reviewer`** system prompt, NOT the coder's. The coder is a code-oriented agent that lacks the doc-invariant contract — routing doc fixes to it is the wrong agent doing work the auditing agent already has full context for. The agent that *audits* the docs is also the agent that *fixes* them (`doc-reviewer.md` § Constraints: "WRITE missing docs directly. You are fully responsible — do not defer to other agents"). NEVER route a `doc`-domain fix to `coder`.
|
|
994
1030
|
|
|
@@ -1011,13 +1047,14 @@ After completeness is verified, clean up the implementation before it reaches re
|
|
|
1011
1047
|
- **Efficiency agent** — flag unnecessary work (redundant computations, duplicate API calls, N+1), missed concurrency, hot-path bloat, recurring no-op updates without change-detection guards, TOCTOU existence checks, memory issues (unbounded structures, missing cleanup), overly broad operations.
|
|
1012
1048
|
|
|
1013
1049
|
4. Aggregate findings from all three agents. For each finding:
|
|
1014
|
-
- **Valid** →
|
|
1015
|
-
- **
|
|
1050
|
+
- **Valid AND in a Domain-Override domain** (the finding's target file matches the `doc`, `security`, or `migration` match rule in "Domain-Override Domains") → do NOT apply inline. Delegate to the domain owner: `doc` → `doc-reviewer` (write mode), `security`/`migration` → `coder`. Even a one-line efficiency fix in `paths.high_risk_modules` or a migration file goes to the owning agent — the orchestrator lacks that domain's invariant contract.
|
|
1051
|
+
- **Valid AND not in a Domain-Override domain** → fix directly (apply edits inline).
|
|
1052
|
+
- **False positive / not worth addressing** → skip, BUT record it (see telemetry). If the skip rests on a "covered by X" / "redundant" / "not needed" rationalization (the same family the AC-Closure Gate guards against), do NOT discard silently — verify the rationale by reading `X`, and if it does not hold, treat the finding as valid.
|
|
1016
1053
|
|
|
1017
|
-
**Telemetry (Fix Application Log)** — for EVERY finding (valid OR skipped) append one row to the tracker's `## Fix Application Log` section per the schema above. Use `domain=simplify-{reuse|quality|efficiency}` matching the originating agent.
|
|
1054
|
+
**Telemetry (Fix Application Log)** — for EVERY finding (valid OR skipped) append one row to the tracker's `## Fix Application Log` section per the schema above. Use `domain=simplify-{reuse|quality|efficiency}` matching the originating agent. Include the `severity` trailing key. Inline: `decision=inline | applied_by=orchestrator | est_lines=<n> | severity=<HIGH|MEDIUM> | finding=<1-line>`. Delegated (domain-override): `decision=<coder|doc-reviewer> | applied_by=<coder|doc-reviewer> | est_lines=<n> | severity=<...> | finding=<1-line>`. Skipped: `decision=skipped | applied_by=- | est_lines=0 | reason=<false-positive|not-worth-addressing>`.
|
|
1018
1055
|
|
|
1019
1056
|
5. After all fixes, run `npm run lint` and `npx tsc --noEmit` to confirm nothing broke.
|
|
1020
|
-
If either fails, fix the regression (up to 2 retries).
|
|
1057
|
+
If either fails, fix the regression (up to **2 retries**). **If it still fails after 2 retries**: do NOT silently continue to Phase 2.6 with a broken tree — log the failure in `## Issues & Flags` as `[SIMPLIFY-REGRESSION]` and invoke `AskUserQuestion` (revert the simplify fixes / keep and have me fix manually / stop the card), mirroring the Phase 3.5 escalation.
|
|
1021
1058
|
|
|
1022
1059
|
6. **Update tracker**: phase = "2.55-simplify DONE", log count of fixes applied (or "clean — 0 fixes").
|
|
1023
1060
|
If any valid finding revealed a reusable pattern or common mistake, append 1-line to `## Lessons Learned`:
|
|
@@ -1041,8 +1078,8 @@ auto-skips on backend-only cards, and BLOCKS the commit on gating findings.
|
|
|
1041
1078
|
| Condition | Action |
|
|
1042
1079
|
|-----------|--------|
|
|
1043
1080
|
| `features.has_e2e_review: false` in `baldart.config.yml` | **SKIP** — log `"e2e-review: SKIP (feature disabled — run `npx baldart configure` to enable)"`. Preserves backwards compatibility for pre-3.18 consumers. |
|
|
1044
|
-
| Card has no `links.design` AND `git diff --name-only` shows no file under `${paths.app_dir}` AND no file under `${paths.components_primitives}` AND no `*.tsx` / `*.css` / `*.scss` / `*.svelte` / `*.vue` anywhere | **SKIP** — log `"e2e-review: SKIP (backend-only card)"`. |
|
|
1045
|
-
| Card type is `docs`, `chore`, or `config` | **SKIP** — same log. |
|
|
1081
|
+
| Card has no `links.design` AND the card's diff (`git diff --name-only "$TRUNK...HEAD"` for this card's committed files, falling back to `HEAD~1..HEAD`) shows no file under `${paths.app_dir}` AND no file under `${paths.components_primitives}` AND no `*.tsx` / `*.css` / `*.scss` / `*.svelte` / `*.vue` anywhere | **SKIP** — log `"e2e-review: SKIP (backend-only card)"`. (Diff against the trunk, NOT a bare `HEAD` — the coder already committed, so a working-tree diff is empty and would false-skip.) |
|
|
1082
|
+
| Card type is `backend`, `api`, `db`, `infra`, `docs`, `chore`, or `config` | **SKIP** — same log. (This list mirrors `/e2e-review`'s OWN Pre-flight skip set so `/new` does not invoke the skill only to have it immediately return `skipped`. A card with no `type` field falls through to the diff-based backend-only check above — do NOT assume a missing type means skip.) |
|
|
1046
1083
|
|
|
1047
1084
|
#### Invocation contract
|
|
1048
1085
|
|
|
@@ -1056,12 +1093,12 @@ When the gate above passes, the orchestrator invokes `/e2e-review` in
|
|
|
1056
1093
|
{
|
|
1057
1094
|
"card_id": "<CARD-ID>",
|
|
1058
1095
|
"worktree_path": "<absolute worktree path>",
|
|
1059
|
-
"mode": "programmatic"
|
|
1060
|
-
"tolerance": "<features.e2e_review.fidelity_tolerance>",
|
|
1061
|
-
"max_self_heal_iterations": "<features.e2e_review.max_self_heal_iterations>"
|
|
1096
|
+
"mode": "programmatic"
|
|
1062
1097
|
}
|
|
1063
1098
|
```
|
|
1064
1099
|
|
|
1100
|
+
Do NOT pass `tolerance` / `max_self_heal_iterations` in the payload — `/e2e-review` reads those from `features.e2e_review.*` in `baldart.config.yml` itself (they are NOT parsed from the invocation payload). Passing them here would be dead keys that silently diverge from the config the skill actually uses.
|
|
1101
|
+
|
|
1065
1102
|
The skill is responsible for: reading the card YAML + `test_plan`, deriving
|
|
1066
1103
|
routes from the diff, walking the 4-level mockup cascade (Figma MCP →
|
|
1067
1104
|
local image → compliance-only → skip), generating the Playwright spec via
|
|
@@ -1089,7 +1126,7 @@ When the gate above passes, the orchestrator invokes `/e2e-review` in
|
|
|
1089
1126
|
| `"skipped"` | Log skip reason. Proceed to Phase 3. |
|
|
1090
1127
|
| `"overridden"` | Log override + reason in `## Issues & Flags` as `[E2E-OVERRIDE] <reason>`. Proceed to Phase 3. |
|
|
1091
1128
|
| `"blocked"` | **STOP the card**. Log findings in tracker + `## Issues & Flags` as `[E2E-BLOCKED] <count> gating findings (<categories>)`. Ask the user whether to (a) override with reason, (b) escalate (open follow-up card), or (c) abandon this card and continue the batch. Do NOT proceed to Phase 3 silently. |
|
|
1092
|
-
| `"error"` | Log error in `## Issues & Flags`. Ask the user whether to retry, skip, or abandon. Do NOT proceed silently. |
|
|
1129
|
+
| `"error"` | Log error in `## Issues & Flags`. Ask the user whether to retry, skip, or abandon. Do NOT proceed silently. **Retry re-entry (defined path, capped):** on "retry", re-enter at step 1 of this Invocation contract — reset the `.baldart/e2e-review/<CARD-ID>/` state dir, re-spawn `/e2e-review` with the SAME payload, and re-parse. **Cap: 2 error-retries per card** (central repair cap, consistent with the other loops). On the 2nd `error`, do NOT re-offer "retry" — re-invoke `AskUserQuestion` with only skip/abandon, so the loop cannot recur unbounded. |
|
|
1093
1130
|
|
|
1094
1131
|
#### Re-run trigger (after Phase 3.7 `/codexreview`)
|
|
1095
1132
|
|
|
@@ -1132,9 +1169,9 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
|
|
|
1132
1169
|
> **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).
|
|
1133
1170
|
|
|
1134
1171
|
12. **Update tracker**: phase = "3-doc-review".
|
|
1135
|
-
13. Build a **Doc Sync Context** block:
|
|
1172
|
+
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):
|
|
1136
1173
|
```bash
|
|
1137
|
-
git diff --name-only HEAD
|
|
1174
|
+
git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD
|
|
1138
1175
|
```
|
|
1139
1176
|
Use the output to build this block:
|
|
1140
1177
|
```
|
|
@@ -1151,10 +1188,10 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
|
|
|
1151
1188
|
- [ ] Backlog card set to DONE? → ${paths.references_dir}/ssot-registry.md entry
|
|
1152
1189
|
- [ ] New external dependency? → agents/architecture.md External Dependencies list
|
|
1153
1190
|
- [ ] Card has `documentation_impact` field? → verify each listed doc is updated
|
|
1154
|
-
- [ ] New `process.env.VAR` added? → entry in `${paths.references_dir}/env-vars.md` (
|
|
1155
|
-
- [ ] Last usage of `process.env.VAR` removed? → mark `status: deprecated` in `${paths.references_dir}/env-vars.md`
|
|
1156
|
-
- [ ] Default value changed in `src/lib/env.ts
|
|
1157
|
-
- [ ] Card
|
|
1191
|
+
- [ ] New `process.env.VAR` added? → entry in `${paths.references_dir}/env-vars.md` (name, scope, required, feature/card, default)
|
|
1192
|
+
- [ ] Last usage of `process.env.VAR` removed? → mark `status: deprecated` in `${paths.references_dir}/env-vars.md` with the date
|
|
1193
|
+
- [ ] Default value changed in the project's env module (e.g. `src/lib/env.ts`)? → update the Default column in `${paths.references_dir}/env-vars.md`
|
|
1194
|
+
- [ ] Card has an `env_vars` field populated? → verify each entry is tracked in `${paths.references_dir}/env-vars.md`
|
|
1158
1195
|
|
|
1159
1196
|
### Related docs to check (per convention map):
|
|
1160
1197
|
- [derive from FRESHNESS_MAP: src/app/api/** → ${paths.references_dir}/api/; src/lib/booking/** → booking.md etc.]
|
|
@@ -1182,51 +1219,56 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
|
|
|
1182
1219
|
doc-reviewer does NOT fix itself — report it with the conflicting code location + the doc
|
|
1183
1220
|
it violates, and the orchestrator routes it to the `security`/code fix path as appropriate.
|
|
1184
1221
|
```
|
|
1185
|
-
Doc-reviewer applies all doc-domain fixes itself. The orchestrator does NOT spawn a coder for doc fixes (since v3.40.0 — `doc` is owned by `doc-reviewer`, see "Domain-Override Domains"). The only doc-reviewer output that leaves this phase unfixed is a doc-drift→bug finding rooted in code,
|
|
1186
|
-
14. **
|
|
1187
|
-
15. **Telemetry** — after doc-reviewer returns, append one row per doc finding to `## Fix Application Log`: `3 | doc | est_lines=<n> | decision=doc-reviewer | applied_by=doc-reviewer | finding=<1-line>`. If 0 findings, append one row: `3 | doc | est_lines=0 | decision=skipped | applied_by=- | reason=no-findings`.
|
|
1188
|
-
16. Run `npm run lint` and `npx tsc --noEmit` to verify nothing broke. If any check fails, apply the self-healing retry loop (up to 3 times, no user prompt).
|
|
1189
|
-
17. **
|
|
1222
|
+
Doc-reviewer applies all doc-domain fixes itself. The orchestrator does NOT spawn a coder for doc fixes (since v3.40.0 — `doc` is owned by `doc-reviewer`, see "Domain-Override Domains"). The only doc-reviewer output that leaves this phase unfixed is a **doc-drift→bug finding rooted in CODE** (the implementation contradicts a documented contract). Route it explicitly: if the conflicting code file matches the `security` Domain-Override match rule (`paths.high_risk_modules`) → spawn `coder` with the finding now, in this phase (a security-class code fix is not deferrable to a `light` Phase 3.7); otherwise carry the finding into the Phase 3.7 `/codexreview` input as a known code-drift bug and let the Phase 3.7 fix sub-loop apply it. Either way, append a Fix Application Log row with `domain=codex-correctness` (NOT `doc`) so telemetry attributes it as a code fix. Do NOT leave it accumulating in the tracker with no fix owner.
|
|
1223
|
+
14. **Knowledge-corpus sync (OPTIONAL — only if the project ships a corpus-sync agent)**: There is NO shipped `obsidian-sync` agent — do NOT dispatch one (a hard dispatch to a non-existent subagent fails silently). Only when the project provides its own knowledge-corpus sync agent (declared in `.baldart/overlays/new.md`) AND doc-reviewer's findings indicate a corpus impact, invoke that agent with the listed paths after the doc fixes are applied. Otherwise skip with a one-line notice (`knowledge-corpus sync: skipped (no corpus-sync agent configured)`). Non-blocking either way.
|
|
1224
|
+
15. **Telemetry** — after doc-reviewer returns, append one row per doc finding to `## Fix Application Log`: `3 | doc | est_lines=<n> | decision=doc-reviewer | applied_by=doc-reviewer | finding=<1-line>`. If 0 findings, append one row: `3 | doc | est_lines=0 | decision=skipped | applied_by=- | reason=no-findings`. **Phase-8 producer (named counter)** — ALSO record the per-card doc-gap counts as a structured line in `## Current Card` (carried into `## Completed Cards` at Phase 5): `doc_gaps: found=<N> fixed=<M>` where `N` = total doc findings doc-reviewer raised and `M` = those it applied. This is the single named producer for Phase 8's `doc_gaps_found` / `doc_gaps_fixed` fields — without it those fields have no upstream write and Phase 8 would hard-code zeros. (D.4a is the team-mode producer of the same counter — see Phase 7 § D.4a.)
|
|
1225
|
+
16. Run `npm run lint` and `npx tsc --noEmit` (when `stack.language` includes typescript) to verify nothing broke. If doc-reviewer touched any source-adjacent file (a `.ts`/`.tsx` helper, a co-located doc export), also run `npm run build`. If any check fails, apply the self-healing retry loop (up to 3 times, no user prompt). **If still failing after 3 retries**: do NOT fall through silently to Phase 3.5 — log `[DOC-PHASE-REGRESSION]` in `## Issues & Flags` and invoke `AskUserQuestion` (revert the doc-phase edits that broke the build / keep and fix manually / stop the card).
|
|
1226
|
+
17. **Telemetry for the step-16 self-heal** — if the retry loop spawned any fix (a code edit to recover from a doc-phase regression), append a Fix Application Log row for it AFTER the loop settles (the step-15 doc telemetry row was written before this loop ran, so it does not capture step-16 fixes). Then update tracker: phase = "3-doc-review DONE", log doc findings count, fixes applied.
|
|
1190
1227
|
If doc-reviewer found a recurring gap, append 1-line to `## Lessons Learned`:
|
|
1191
1228
|
`DOC: <pattern>`
|
|
1192
1229
|
|
|
1193
1230
|
### Phase 3.5 — QA Validation
|
|
1194
1231
|
|
|
1195
1232
|
18. **Update tracker**: phase = "3.5-qa".
|
|
1196
|
-
19. **Select QA profile**: READ the card's `review_profile` field (use verbatim); only compute
|
|
1233
|
+
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).
|
|
1197
1234
|
20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
|
|
1198
|
-
21. **If profile is LIGHT**: SKIP qa-sentinel
|
|
1235
|
+
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.
|
|
1199
1236
|
22. **If profile is BALANCED or DEEP**: invoke the **`qa-sentinel`** agent (subagent_type: `qa-sentinel`) via Task tool with the following context:
|
|
1200
1237
|
|
|
1201
1238
|
```
|
|
1202
|
-
Run
|
|
1239
|
+
Run QA gates on card <CARD-ID> at the tier dictated by the QA profile below (do NOT default to FULL).
|
|
1240
|
+
You are a MECHANICAL GATE-RUNNER: run the gates, return a PASS/FAIL gate table + confidence.
|
|
1241
|
+
Do NOT read source files to analyze logic, do NOT emit a BLOCKER/MAJOR/MINOR severity taxonomy,
|
|
1242
|
+
do NOT do collateral-impact analysis, and do NOT write tests.
|
|
1203
1243
|
|
|
1204
1244
|
Context:
|
|
1205
|
-
- Worktree path: <worktree-path>
|
|
1245
|
+
- Worktree path: <worktree-path> — `cd` into it before running any gate
|
|
1206
1246
|
- Branch: <branch-name>
|
|
1207
1247
|
- Changed files: <list from implementation phase>
|
|
1208
1248
|
- QA profile: [balanced | deep]
|
|
1209
1249
|
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1250
|
+
Tier contract: balanced → SCOPED (related tests on touched modules); deep → FULL suite.
|
|
1251
|
+
Only path-based risk drift (auth/permission/payment/schema/migration/API contract in the diff)
|
|
1252
|
+
may escalate balanced→FULL. File count never escalates.
|
|
1253
|
+
|
|
1254
|
+
E2E is NOT your job (run by the /e2e-review skill in Phase 2.6) — do NOT run Playwright.
|
|
1255
|
+
Run the gates: lint, tsc (when stack.language includes typescript), test (per tier), build, markdownlint.
|
|
1213
1256
|
Do NOT verify acceptance criteria (Phase 2.5 already did this).
|
|
1214
|
-
Do NOT analyze code for bugs/patterns (
|
|
1215
|
-
Do NOT write recommendations or follow-up actions.
|
|
1257
|
+
Do NOT analyze code for bugs/patterns (the per-card /codexreview gate in Phase 3.7 does this).
|
|
1216
1258
|
|
|
1217
1259
|
Write the gate results + verdict to: /qa/<CARD-ID>.md
|
|
1218
1260
|
Report should be under 40 lines.
|
|
1219
|
-
Return verdict: PASS or FAIL.
|
|
1261
|
+
Return verdict: PASS or FAIL (+ the per-gate table).
|
|
1220
1262
|
```
|
|
1221
1263
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
- Spawn the **coder** agent to fix
|
|
1264
|
+
23. **Read qa-sentinel's output.** Verify the findings file was written to `/qa/<CARD-ID>.md`. **If the file is absent** (qa-sentinel returned a verdict but did not write it): re-invoke qa-sentinel once asking it to (re-)write the file; if still absent, treat the verdict from the return message as authoritative, log `[QA] findings file missing — used return verdict` in `## Issues & Flags`, and pass the captured gate output (not a missing path) to any fix coder.
|
|
1265
|
+
24. **If QA verdict is FAIL** (one or more gates failed):
|
|
1266
|
+
- Spawn the **coder** agent to fix the FAILING GATES (pass it the findings file path + the failing-gate output — NOT a severity-ranked finding list; qa-sentinel does not emit one). Do NOT ask the user.
|
|
1225
1267
|
- After coder fixes, re-invoke `qa-sentinel` in the same mode to re-validate. Repeat up to **2 times**.
|
|
1226
1268
|
- If still FAIL after 2 retries: log in `## Issues & Flags` and **ask the user** whether to proceed or stop.
|
|
1227
1269
|
- The commit in Phase 4 MUST NOT happen until QA verdict is PASS (or user explicitly overrides).
|
|
1228
|
-
- **Telemetry** — after each coder spawn, append one row per
|
|
1229
|
-
|
|
1270
|
+
- **Telemetry** — after each coder spawn, append one row per failing-gate fix to `## Fix Application Log`: `3.5 | qa-blocker | est_lines=<n> | decision=coder | applied_by=coder | retry=<0|1|2>`. After PASS without any spawn (initial verdict PASS), append one row: `3.5 | qa-none | est_lines=0 | decision=skipped | applied_by=- | reason=qa-pass`.
|
|
1271
|
+
25. **Update tracker**: phase = "3.5-qa DONE", log: profile used, tier run (SCOPED/FULL) + any risk-drift escalation, verdict (PASS/FAIL/SKIP), confidence %, failing gates (which of lint/tsc/test/build/markdownlint), findings file path. (qa-sentinel returns a per-gate PASS/FAIL table, not a blockers/majors/minors split — do not invent one.) **Phase-8 producer (named flag)** — ALSO record `qa_first_attempt: <pass|fail>` on the card's `## Completed Cards` QA line: `pass` ⟺ the FIRST qa-sentinel invocation (step 22, retry=0) returned PASS with no step-24 coder spawn; `fail` ⟺ a retry was needed (or the profile reached PASS only after a fix). For `SKIP`/`LIGHT` cards (qa-sentinel not run) record `qa_first_attempt: n/a`. This is the single named producer for Phase 8's `qa_pass_first_attempt_rate` — the tracker otherwise logs only the final verdict, so the first-attempt signal must be tagged here at the source.
|
|
1230
1272
|
|
|
1231
1273
|
### Phase 3.7 — Pre-Merge Codex Review Gate (MANDATORY — UNCONDITIONAL)
|
|
1232
1274
|
|
|
@@ -1238,46 +1280,47 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
|
|
|
1238
1280
|
|
|
1239
1281
|
Run this exact bash block in the worktree. It is deterministic (grep + path match), not LLM-discretionary.
|
|
1240
1282
|
|
|
1283
|
+
`$TRUNK` is the trunk branch resolved in Phase 0 (`git.trunk_branch`, default `develop`). `$HIGH_RISK_RE` is an alternation built from `paths.high_risk_modules` in `baldart.config.yml` (e.g. `path1|path2|withAuth`). **If `paths.high_risk_modules` is absent, the path-based triggers (#1) emit a one-line diagnostic and match nothing — no hardcoded project path is baked in.**
|
|
1284
|
+
|
|
1241
1285
|
```bash
|
|
1242
1286
|
cd <worktree-path>
|
|
1243
1287
|
CARD_ID="<CARD-ID>"
|
|
1244
|
-
CARD_FILE="$(find
|
|
1245
|
-
|
|
1288
|
+
CARD_FILE="$(find "${paths.backlog_dir:-../../backlog}" -name "${CARD_ID}*.yml" 2>/dev/null | head -1)"
|
|
1289
|
+
# Detect what THIS card's commits changed against the trunk (post-commit), with an uncommitted fallback:
|
|
1290
|
+
CHANGED="$(git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD)"
|
|
1291
|
+
# High-risk path alternation from config (empty when paths.high_risk_modules is unset):
|
|
1292
|
+
HIGH_RISK_RE="<alternation of paths.high_risk_modules entries, or empty>"
|
|
1246
1293
|
|
|
1247
1294
|
TRIGGERS=()
|
|
1248
1295
|
|
|
1249
|
-
# Trigger #1 —
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
# Trigger #4 — Dead-code resurrection (card text + commit messages)
|
|
1262
|
-
{ cat "$CARD_FILE" 2>/dev/null; git log --format=%B develop...HEAD 2>/dev/null; } \
|
|
1296
|
+
# Trigger #1 — High-risk module (auth / permission / payment / shared scoring-or-ranking primitive)
|
|
1297
|
+
# Sourced from paths.high_risk_modules — NOT a hardcoded project path.
|
|
1298
|
+
if [ -n "$HIGH_RISK_RE" ]; then
|
|
1299
|
+
echo "$CHANGED" | grep -qE "$HIGH_RISK_RE" \
|
|
1300
|
+
&& TRIGGERS+=("#1: high-risk module (paths.high_risk_modules)")
|
|
1301
|
+
else
|
|
1302
|
+
echo "[DETECTOR] paths.high_risk_modules absent — path-based high-risk trigger skipped" >&2
|
|
1303
|
+
fi
|
|
1304
|
+
|
|
1305
|
+
# Trigger #2 — Dead-code resurrection (card text + commit messages)
|
|
1306
|
+
{ cat "$CARD_FILE" 2>/dev/null; git log --format=%B "$TRUNK...HEAD" 2>/dev/null; } \
|
|
1263
1307
|
| grep -qiE 'dead code|unreachable|resurrect' \
|
|
1264
|
-
&& TRIGGERS+=("#
|
|
1265
|
-
|
|
1266
|
-
# Trigger #
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
&& TRIGGERS+=("#6: Reference-aliasing mutation pattern (BUG-0558 family)")
|
|
1308
|
+
&& TRIGGERS+=("#2: Dead-code resurrection")
|
|
1309
|
+
|
|
1310
|
+
# Trigger #3 — Reference-aliasing mutation pattern (in-place array reset + push)
|
|
1311
|
+
# Card introduces or modifies an exported helper AND a call site in the diff mutates an input
|
|
1312
|
+
# array in place via `length = 0` + `push(...result)`. Even with a local identity guard, the
|
|
1313
|
+
# high-risk gate runs adversarial review to confirm the contract is robust against future callers.
|
|
1314
|
+
# Iterate file-by-file safely (no unquoted xargs filename expansion):
|
|
1315
|
+
RESET=""; PUSH=""
|
|
1316
|
+
while IFS= read -r f; do
|
|
1317
|
+
[ -n "$f" ] || continue
|
|
1318
|
+
C="$(git show "HEAD:$f" 2>/dev/null)" || continue
|
|
1319
|
+
printf '%s' "$C" | grep -qE '\.length\s*=\s*0' && RESET=1
|
|
1320
|
+
printf '%s' "$C" | grep -qE '\.push\(\s*\.\.\.' && PUSH=1
|
|
1321
|
+
done <<< "$CHANGED"
|
|
1322
|
+
[ -n "$RESET" ] && [ -n "$PUSH" ] \
|
|
1323
|
+
&& TRIGGERS+=("#3: Reference-aliasing mutation pattern")
|
|
1281
1324
|
|
|
1282
1325
|
printf '%s\n' "${TRIGGERS[@]}"
|
|
1283
1326
|
```
|
|
@@ -1331,8 +1374,9 @@ For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH var
|
|
|
1331
1374
|
Then dump the card diff (reviewer grounding) and write the lean contract `/codexreview` consumes:
|
|
1332
1375
|
```bash
|
|
1333
1376
|
cd <worktree-path>
|
|
1334
|
-
|
|
1335
|
-
|
|
1377
|
+
# $TRUNK = the trunk branch resolved in Phase 0 (git.trunk_branch)
|
|
1378
|
+
git diff "$TRUNK...HEAD" -- <card files from ownership map> > /tmp/diff-<CARD-ID>.txt 2>/dev/null \
|
|
1379
|
+
|| git diff HEAD~1..HEAD > /tmp/diff-<CARD-ID>.txt
|
|
1336
1380
|
```
|
|
1337
1381
|
Write `/tmp/codexreview-lean-<CARD-ID>.json`:
|
|
1338
1382
|
```json
|
|
@@ -1365,26 +1409,33 @@ For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH var
|
|
|
1365
1409
|
(since v3.38.0). `code-reviewer` + Step 3 FP-gate + Step 4 report ALWAYS run. (`full` = standard
|
|
1366
1410
|
pipeline incl. Codex adversarial, minus the duplicate doc-reviewer.)
|
|
1367
1411
|
|
|
1368
|
-
3. **Read the consolidated report
|
|
1412
|
+
3. **Read the consolidated report**. `/codexreview` writes it to `/tmp/codexreview-report-<TIMESTAMP>.md` and RETURNS that exact path in its Skill-tool result — use the returned path, do NOT guess the timestamp. If the return value did not surface the path, locate the newest report whose body names this `<CARD-ID>` (`grep -l "<CARD-ID>" /tmp/codexreview-report-*.md | xargs ls -t | head -1`), never just the newest file by mtime (a parallel card's report could be newer). Extract:
|
|
1369
1413
|
- Verified BLOCKER count
|
|
1370
1414
|
- Verified HIGH count
|
|
1371
|
-
- List of `[ripple-expanded]` findings (Step 3.5 widened scope)
|
|
1415
|
+
- List of `[ripple-expanded]` findings (Step 3.5 widened scope). At `light` profile Step 3.5 CoVe does not run, so this list is structurally empty — log `ripple-expanded: 0 (CoVe not run at light)` rather than a bare `0`, so audits can tell "not attempted" apart from "attempted, none found".
|
|
1372
1416
|
|
|
1373
1417
|
4. **Apply fix sub-loop** (mirror of Phase 3.5 retry pattern):
|
|
1374
|
-
- If 0 BLOCKER and 0 HIGH → log `verdict: PASS — proceeding to Phase 4` in tracker. Done.
|
|
1375
|
-
- If 1+ BLOCKER OR 1+ HIGH → spawn `coder` agent with the report path + list of VERIFIED bugs
|
|
1376
|
-
- If still BLOCKER/HIGH after 2 retries → log in `## Issues & Flags` and **ask the user** whether to proceed, escalate, or stop. The Phase 4 commit MUST NOT happen until
|
|
1418
|
+
- If 0 BLOCKER and 0 HIGH → log `verdict: PASS — proceeding to Phase 4` in tracker. Done. (MEDIUM/LOW findings are advisory at this per-card gate; they are not silently lost — the post-batch **Final-review FULL gate** applies every VERIFIED finding ≥ MEDIUM. Log the MEDIUM count in the tracker so it is visible.)
|
|
1419
|
+
- If 1+ BLOCKER OR 1+ HIGH → spawn `coder` agent with the report path + list of VERIFIED bugs. **At `full` profile** the report contains Codex-suggested inline patches: pass them and have the coder **apply the suggested patches** with the right system prompt (project conventions, naming, testing patterns) — it does NOT re-do the analysis or re-grep (since v3.28.3), BUT it MUST first confirm each patch still applies against the current file state (prior fix-loop iterations may have shifted line offsets); if a patch no longer applies cleanly, the coder re-locates the target by content and applies the equivalent edit rather than a stale-offset verbatim paste. **At `light` profile** no Codex adversarial patches exist (the pass was dropped) — the findings come from `code-reviewer`; brief the coder accordingly (apply the `code-reviewer` fix direction; there are no Codex patches to paste). After coder fixes, **re-write the lean contract `/tmp/codexreview-lean-<CARD-ID>.json` (it is consumed-once and deleted by `/codexreview`)** and re-invoke `/codexreview` via the Skill tool with `args: <CARD-ID>` (NOT a bare prose mention — the card ID MUST be passed so the retry reviews THIS card, not an inferred one). Repeat **max 2 times**.
|
|
1420
|
+
- If still BLOCKER/HIGH after 2 retries → log in `## Issues & Flags` and **ask the user** whether to proceed, escalate, or stop. The Phase 4 commit MUST NOT happen until the Pre-Merge Codex Review verdict is PASS or user explicitly overrides.
|
|
1377
1421
|
- **Telemetry** — for EVERY codex finding processed (verified BLOCKER, verified HIGH, or false-positive-filtered), append one row to `## Fix Application Log`: `3.7 | codex-<security|correctness|other> | est_lines=<n> | decision=<coder|skipped> | applied_by=<coder|-> | severity=<BLOCKER|HIGH|FALSE-POSITIVE> | retry=<n>`. Classify domain: `security` for findings touching RLS / auth / permissions / payments; `correctness` for logic / data integrity / race conditions; `other` for everything else.
|
|
1378
1422
|
|
|
1379
|
-
5. **Update tracker**: phase = `3.7-
|
|
1423
|
+
5. **Update tracker**: phase = `3.7-codexgate DONE` (the gate runs unconditionally for every card — the legacy `3.7-highrisk` name implied it only fired on high-risk cards, which is no longer true), log final verdict, retry count, list of fixed findings, and the report path.
|
|
1424
|
+
|
|
1425
|
+
6. **E2E re-run obligation check (enforces the Phase 2.6 re-run trigger HERE)** — if this Phase 3.7 fix sub-loop modified any file under `${paths.app_dir}`, `${paths.components_primitives}`, or any `*.css` / `*.scss`, you MUST re-invoke `/e2e-review` (programmatic mode, same `.baldart/e2e-review/<CARD-ID>/` state dir) BEFORE the Phase 4 commit and resolve its verdict per the Phase 2.6 gating-logic table. Log `e2e-rerun: triggered` or `e2e-rerun: not-needed (no UI files touched in 3.7)` in the tracker so Phase 4 can assert it. Do NOT defer this to "it's documented in Phase 2.6" — the check fires here, where the fixes happen.
|
|
1380
1426
|
|
|
1381
1427
|
#### Why deterministic detector + agent pipeline
|
|
1382
1428
|
|
|
1383
1429
|
The detector (Step A) is bash + grep — guaranteed to run, no LLM skip. The downstream pipeline (Step C) is the existing `/codexreview` skill — fully tested, includes Codex adversarial review and Step 3.5 cross-agent CoVe. This combination ensures the AGENTS.md "MUST run BEFORE merge" rule is enforced reliably.
|
|
1384
1430
|
|
|
1431
|
+
**Crash handling**: if `/codexreview` (or its fix-loop `coder`) crashes mid-phase, apply the "Sub-agent failure protocol" (below). Treat this gate as a **mandatory gate, NOT a non-domain-override fallback** — `/codexreview` covers the `security` domain (auth/payment/permission findings), so a crash that cannot be recovered by one retry STOPS the pipeline and routes to `AskUserQuestion`; do NOT rationalize it as "non-domain-override" and inline-bypass the merge gate.
|
|
1432
|
+
|
|
1385
1433
|
### Phase 4 — Commit (in worktree, NO merge yet)
|
|
1386
|
-
|
|
1387
|
-
|
|
1434
|
+
|
|
1435
|
+
> Sequential-mode global step numbering resumes here at 26 (Phase 3.5 ended at 25; Phase 3.7 used its own local C.0–C.6 counter). The tracker phase-string `4-commit` therefore maps to step 26, NOT a second step 25.
|
|
1436
|
+
|
|
1437
|
+
26. **Update tracker**: phase = "4-commit". **Entry assertion** — before committing, verify the Phase 3.7 e2e re-run obligation was honored: read the tracker for `e2e-rerun: triggered` / `e2e-rerun: not-needed`. If Phase 3.7 touched UI files but no `e2e-rerun` entry exists, do NOT commit yet — go run the re-run per Phase 3.7 step 6 first. Also confirm Phase 3.5/3.7 fixes did not leave lint/tsc broken: if the Phase 3.7 fix sub-loop applied any patch, run `npm run lint` + `npx tsc --noEmit` (when typescript) once before committing.
|
|
1438
|
+
27. Stage and commit **all changes together** in the worktree using format `[CARD-ID] Brief description` (MUST per AGENTS.md). Include all relevant files — implementation, review fixes, QA-driven fixes, and doc updates in a single commit. Do NOT merge or push yet — that happens post-batch.
|
|
1388
1439
|
- **IMPORTANT — explicit staging**: NEVER use `git add -A` or `git add .`. Always stage files by explicit name:
|
|
1389
1440
|
```bash
|
|
1390
1441
|
cd <worktree-path>
|
|
@@ -1397,20 +1448,22 @@ The detector (Step A) is bash + grep — guaranteed to run, no LLM skip. The dow
|
|
|
1397
1448
|
git commit -m "[CARD-ID] Brief description"
|
|
1398
1449
|
```
|
|
1399
1450
|
- **WORKTREE COMMIT RULE — NEVER use `git stash` in worktrees.** Stashes are globally shared across all worktrees (`refs/stash` via `git.commondir`). A stash created in one worktree can be popped by another, causing conflicts, data loss, and cascading merge failures. The file ownership map ensures no overlap between cards — explicit staging is sufficient isolation. The stash pattern in AGENTS.md applies ONLY to the main repo working tree.
|
|
1400
|
-
- **If commit fails
|
|
1451
|
+
- **If commit fails**:
|
|
1452
|
+
0. **"Nothing to commit" is NOT a failure** — if the error is `nothing to commit, working tree clean`, all changes were already committed by a prior step (e.g. doc-reviewer committed its own docs, or a Phase 3.7 fix was already committed). Treat the card commit as already done, record the existing HEAD hash, and proceed to step 28 (Mark card DONE) — do NOT enter the COMMIT_LOCK / re-stage loop.
|
|
1401
1453
|
1. **Check for stale COMMIT_LOCK first** — parallel agents and crashed processes leave stale lock files. Always clear before retry:
|
|
1402
1454
|
```bash
|
|
1403
1455
|
rm -f <main-repo>/.git/worktrees/<worktree-name>/COMMIT_LOCK 2>/dev/null
|
|
1404
1456
|
```
|
|
1405
|
-
2. Re-stage the same files explicitly and retry. Never run `git commit` alone after a failure — the staging area may have been altered by lint-staged auto-fixes. If lint-staged removed an "unused" variable that IS used by code in a later card, check `git diff` to see what changed, restore the needed code, re-stage, and retry.
|
|
1457
|
+
2. Re-stage the same files explicitly and retry. Never run `git commit` alone after a failure — the staging area may have been altered by lint-staged auto-fixes. If lint-staged removed an "unused" variable that IS used by code in a later card, check `git diff` to see what changed, restore the needed code (explicit file write — **never `git stash pop` in a worktree**), re-stage, and retry.
|
|
1458
|
+
3. **Retry cap + escalation** — retry the commit at most **2 times**. If it still fails (e.g. a pre-commit / doc-freshness rule that cannot be satisfied without human input), log the failure in `## Issues & Flags` as `[COMMIT-BLOCKED] <error>` and invoke `AskUserQuestion`: (a) fix the blocking condition manually and let me retry, (b) hand off the worktree intact, (c) abandon this card and continue the batch. Do NOT loop indefinitely and do NOT silently proceed to step 28 with an uncommitted card.
|
|
1406
1459
|
- The Claude Code pre-commit hook automatically skips for worktree commits (Husky handles checks natively in the worktree).
|
|
1407
|
-
|
|
1460
|
+
28. **Mark card DONE (MANDATORY — do NOT skip)**:
|
|
1408
1461
|
a. Edit the backlog YAML (`${paths.backlog_dir}/<CARD-ID>.yml`): set `status: DONE`, add `completed_date: <today>`.
|
|
1409
1462
|
b. Add implementation notes summarizing what was built.
|
|
1410
1463
|
c. **Update `${paths.references_dir}/ssot-registry.md`** — add/update the entry for this card's feature area. The pre-commit doc-freshness hook BLOCKS commits that touch `backlog/` without a corresponding ssot-registry update. Always include ssot-registry.md in the same commit as the backlog YAML.
|
|
1411
1464
|
d. **Verify the write**: re-read the YAML file and confirm `status: DONE` is present. If not, retry the edit.
|
|
1412
|
-
e. Stage BOTH the updated YAML AND ssot-registry.md, then commit (or as an immediate follow-up commit if Phase 4 commit already happened).
|
|
1413
|
-
|
|
1465
|
+
e. Stage BOTH the updated YAML AND ssot-registry.md, then commit (or as an immediate follow-up commit if the Phase 4 implementation commit already happened). When this produces a SECOND commit for the card, record BOTH hashes in the tracker (`commit: <impl-hash> + <done-hash>`) so traceability/bisect is unambiguous.
|
|
1466
|
+
29. **Update tracker**: move card to `## Completed Cards` with commit hash(es), summary, flags, **and `card_status: DONE (verified)`**.
|
|
1414
1467
|
|
|
1415
1468
|
### Sub-agent failure protocol (since v3.28.3)
|
|
1416
1469
|
|
|
@@ -1424,16 +1477,16 @@ If any sub-agent **crashes or errors** during any phase, follow this 4-step prot
|
|
|
1424
1477
|
Never block the pipeline indefinitely — recover and continue per the rules above. AskUserQuestion in step 3 is bounded by normal user response time.
|
|
1425
1478
|
|
|
1426
1479
|
### Phase 5 — Context Clean & Continue
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1480
|
+
30. Archive the card from Active Code Context in `${paths.references_dir}/project-status.md`.
|
|
1481
|
+
31. **CONTEXT PURGE**: After updating the tracker, deliberately forget the implementation details of this card. From this point forward, you should NOT reference any code, file contents, or review details from this card — only the summary in the tracker. If you need to recall what happened, read the tracker file. This keeps your working context lean for the next card.
|
|
1482
|
+
32. **Update tracker**: clear `## Current Card`, move to next pending card.
|
|
1483
|
+
33. **Move to the next card** — restart the per-card pipeline at **Phase 1 (Claim & Context)** for the next pending card in `## Card Queue`. Do NOT re-run Phase 0 (workspace hygiene runs once per batch) and do NOT re-run Pre-flight worktree setup (the worktree already exists). When all cards in the queue are done, proceed to **Final review**.
|
|
1431
1484
|
|
|
1432
1485
|
---
|
|
1433
1486
|
|
|
1434
1487
|
## Final review (after all cards)
|
|
1435
1488
|
|
|
1436
|
-
> **Primary code reviewer: Codex (
|
|
1489
|
+
> **Primary code reviewer: Codex (a non-Anthropic frontier model, via `codex-companion.mjs`)** — cross-model validation with built-in FP filtering.
|
|
1437
1490
|
> Claude `code-reviewer` is the automatic fallback if Codex is unavailable.
|
|
1438
1491
|
> The `/codexreview` command remains available for standalone reviews on demand.
|
|
1439
1492
|
|
|
@@ -1475,23 +1528,36 @@ Once ALL cards are committed in the worktree:
|
|
|
1475
1528
|
|
|
1476
1529
|
### Step F.2 — Architecture baseline
|
|
1477
1530
|
|
|
1478
|
-
5.
|
|
1479
|
-
|
|
1480
|
-
|
|
1531
|
+
5. **Reuse per-card baselines before re-spawning (dedup).** Phase 1 step 5b already persisted one
|
|
1532
|
+
`/tmp/arch-baseline-<CARD-ID>.md` per card. Before spawning `codebase-architect` for the batch
|
|
1533
|
+
scope, check whether every card in the batch already has a readable baseline file:
|
|
1534
|
+
```bash
|
|
1535
|
+
MISSING=()
|
|
1536
|
+
for c in <ALL-CARD-IDS>; do [ -s "/tmp/arch-baseline-$c.md" ] || MISSING+=("$c"); done
|
|
1537
|
+
printf '%s\n' "${MISSING[@]}"
|
|
1538
|
+
```
|
|
1539
|
+
- **All present** → do NOT re-spawn the architect for the full batch. Concatenate the per-card
|
|
1540
|
+
baselines into `${ARCH_BASELINE}` (they already cover every touched file across the batch) and
|
|
1541
|
+
proceed to F.3. Log `f.2-arch: reused N per-card baselines (no re-spawn)` in the tracker. This
|
|
1542
|
+
avoids the N+1 architect invocations the per-card persistence was designed to prevent.
|
|
1543
|
+
- **Any missing** (a card was added late, or a baseline was purged) → invoke **codebase-architect**
|
|
1544
|
+
ONCE over the batch scope to map existing architecture, critical patterns, and high-risk code
|
|
1545
|
+
paths for regression. Persist its output to `/tmp/arch-baseline-batch-<FIRST-CARD-ID>.md` and use
|
|
1546
|
+
that as `${ARCH_BASELINE}`. Log `f.2-arch: re-spawned (missing baselines: <list>)`. Do NOT spawn
|
|
1547
|
+
the architect more than once for the batch — it is the single grounding context for all
|
|
1548
|
+
downstream review agents.
|
|
1481
1549
|
|
|
1482
1550
|
### Step F.3 — Codex deep code review (primary) + Claude agents (support)
|
|
1483
1551
|
|
|
1484
|
-
> **Primary reviewer: Codex (
|
|
1485
|
-
> `/codexreview` protocol: scope resolution, architecture baseline, parallel deep review,
|
|
1486
|
-
> and mandatory false-positive validation. Claude agents provide doc review and supplementary checks.
|
|
1552
|
+
> **Primary reviewer: Codex (a non-Anthropic frontier model, via `codex-companion.mjs`)** — cross-model validation. This is a SINGLE-MODEL Codex pass over the batch diff (scope + review + self-FP-check in one task) — it is NOT the full multi-agent `/codexreview` command pipeline (no sub-agent spawning, no Step 3.5 CoVe). The full per-card `/codexreview` already ran in Phase 3.7; this final pass is the cross-model batch-wide sweep. Claude agents (doc-reviewer, api-perf-cost-auditor) provide doc review and supplementary checks; qa-sentinel runs gates only.
|
|
1487
1553
|
|
|
1488
|
-
6. **Launch Codex code review** via `Bash` with `run_in_background: true` and `timeout: 600000` (10 min):
|
|
1554
|
+
6. **Launch Codex code review** via `Bash` with `run_in_background: true` and `timeout: 600000` (10 min). **The companion script is invoked WITHOUT `--wait`** so the Bash call returns immediately and the orchestrator can fire the parallel Claude agents in step 7; poll `$REVIEW_FILE` for completion in F.4 (it is `tee`-d, so it fills as Codex runs and is complete when the background task finishes). Combining `run_in_background: true` with `--wait` would block the shell and defeat the parallelism — do NOT pass `--wait` here.
|
|
1489
1555
|
|
|
1490
1556
|
```bash
|
|
1491
|
-
REVIEW_FILE="/tmp/codexreview-batch
|
|
1557
|
+
REVIEW_FILE="/tmp/codexreview-batch-<FIRST-CARD-ID>-<SESSION-ID>.md" && \
|
|
1492
1558
|
CODEX_SCRIPT="$(ls -d ~/.claude/plugins/marketplaces/openai-codex/plugins/codex/scripts/codex-companion.mjs ~/.claude/plugins/cache/openai-codex/codex/*/scripts/codex-companion.mjs 2>/dev/null | sort -V | tail -1)" && \
|
|
1493
|
-
[ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" && exit 1; \
|
|
1494
|
-
node "$CODEX_SCRIPT" task
|
|
1559
|
+
[ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" | tee "$REVIEW_FILE" && exit 1; \
|
|
1560
|
+
node "$CODEX_SCRIPT" task "
|
|
1495
1561
|
Run a deep multi-agent code review for these backlog cards. This is a post-implementation
|
|
1496
1562
|
review — the code is already written and committed. Your job is to find bugs, regressions,
|
|
1497
1563
|
security issues, and quality problems.
|
|
@@ -1534,45 +1600,66 @@ Once ALL cards are committed in the worktree:
|
|
|
1534
1600
|
|
|
1535
1601
|
7. **In parallel with Codex**, launch Claude support agents (single message):
|
|
1536
1602
|
|
|
1537
|
-
| Agent | `subagent_type` | Focus |
|
|
1538
|
-
|
|
1539
|
-
| **doc-reviewer** | `doc-reviewer` | Cross-card doc consistency, ssot-registry completeness, invariants |
|
|
1540
|
-
| **api-perf-cost-auditor** | `api-perf-cost-auditor` | API/data/performance/cost defects (skip if no API/data files in scope) |
|
|
1541
|
-
| **qa-sentinel** | `qa-sentinel` |
|
|
1603
|
+
| Agent | `subagent_type` | Focus | Output |
|
|
1604
|
+
|-------|-----------------|-------|--------|
|
|
1605
|
+
| **doc-reviewer** | `doc-reviewer` | Cross-card doc consistency, ssot-registry completeness, invariants | Findings: `finding_id`, `title`, `severity`, `confidence`, `evidence`, `minimal_fix_direction` |
|
|
1606
|
+
| **api-perf-cost-auditor** | `api-perf-cost-auditor` | API/data/performance/cost defects (skip if no API/data files in scope) | Same findings schema |
|
|
1607
|
+
| **qa-sentinel** | `qa-sentinel` | **Mechanical gates ONLY** over the batch scope (lint, tsc, full test suite, build, `npm audit`, markdownlint) | A PASS/FAIL gate table — NOT a findings list. qa-sentinel does not read source files, does not emit severities, and does not do edge-case/reproducibility analysis (its system prompt forbids it). A gate FAILURE feeds the fix-loop the same way a VERIFIED finding does. |
|
|
1542
1608
|
|
|
1543
|
-
|
|
1544
|
-
|
|
1609
|
+
The two code-aware agents (doc-reviewer, api-perf-cost-auditor) receive: card IDs, YAML, `review_scope_files`, codebase-architect baseline, and a Budget Block per the `/codexreview` Step 2 contract (`framework/.claude/commands/codexreview.md`). qa-sentinel receives only the worktree path + the changed-file list and runs gates. Code-correctness/edge-case analysis is Codex's job (and the per-card `/codexreview` already ran) — do NOT ask qa-sentinel to produce code findings.
|
|
1610
|
+
|
|
1611
|
+
**Fan-out completion barrier (BLOCKING before F.4).** The three Claude agents write to a shared
|
|
1612
|
+
findings pool that F.4 step 9 fans in. Before F.4 reads ANY finding, you MUST have collected the
|
|
1613
|
+
return value of ALL THREE Task invocations from step 7 (doc-reviewer, api-perf-cost-auditor,
|
|
1614
|
+
qa-sentinel) — never start the merge while a Task is still in flight. Because step 7 launches all
|
|
1615
|
+
three in a single message, the harness returns when all three complete; do NOT proceed to step 9
|
|
1616
|
+
on a partial set. (The Codex background task has its OWN barrier — step 8 below polls `$REVIEW_FILE`
|
|
1617
|
+
for completion. The two barriers are independent: wait for BOTH the three Claude Tasks AND the
|
|
1618
|
+
Codex background task before merging.)
|
|
1545
1619
|
|
|
1546
1620
|
### Step F.4 — Collect & merge findings
|
|
1547
1621
|
|
|
1548
|
-
8. **Read Codex findings** from `$REVIEW_FILE` after the background command completes
|
|
1622
|
+
8. **Read Codex findings** from `$REVIEW_FILE` after the background command completes (the background
|
|
1623
|
+
task was launched with `timeout: 600000` in step 6 — that 10-min window is the max wait).
|
|
1549
1624
|
- If file exists and contains findings → use as **primary code review source**.
|
|
1550
1625
|
- If file is empty, missing, or contains `CODEX_NOT_FOUND` → **fallback**: spawn `code-reviewer`
|
|
1551
1626
|
agent (subagent_type: `code-reviewer`) with the same scope and instructions. Log fallback
|
|
1552
1627
|
reason in tracker: `"Codex unavailable — fallback to Claude code-reviewer"`.
|
|
1628
|
+
- **TIMED_OUT branch:** if the 10-min window elapses and `$REVIEW_FILE` still has no terminal
|
|
1629
|
+
output (no findings block and no `CODEX_NOT_FOUND`), treat the Codex pass as **TIMED_OUT** — do
|
|
1630
|
+
NOT block the merge gate waiting indefinitely and do NOT leave the task silently "in-progress".
|
|
1631
|
+
Log `f.3-codex: TIMED_OUT` in `## Issues & Flags` and take the SAME `code-reviewer` fallback as
|
|
1632
|
+
the unavailable case, so the final merge gate still gets a full code review.
|
|
1553
1633
|
|
|
1554
1634
|
9. **Merge all findings** (Codex + Claude agents) into a consolidated list.
|
|
1555
1635
|
- Codex findings are already FP-validated (Step F.3 protocol includes it).
|
|
1556
|
-
- Claude agent findings with `confidence < 80` → cross-validate
|
|
1636
|
+
- Claude agent findings with `confidence < 80` → cross-validate by spawning **`code-reviewer`** as the static validator over the cited file:line; on disagreement between the originating agent and `code-reviewer`, classify the finding `NEEDS_MANUAL_CONFIRMATION` (do NOT silently drop it). (Naming the validator avoids the inconsistent "some second agent" interpretation.)
|
|
1557
1637
|
- Classify: `VERIFIED` | `FALSE_POSITIVE` | `NEEDS_MANUAL_CONFIRMATION`.
|
|
1558
|
-
-
|
|
1638
|
+
- `VERIFIED` findings proceed to fixes. **`NEEDS_MANUAL_CONFIRMATION` findings are NOT discarded** — list them in `## Issues & Flags` and surface them to the user via `AskUserQuestion` (treat as VERIFIED, treat as FALSE_POSITIVE, or hand off) before merge. Only `FALSE_POSITIVE` are dropped.
|
|
1559
1639
|
|
|
1560
1640
|
### Step F.5 — Apply fixes and final build
|
|
1561
1641
|
|
|
1562
1642
|
10. **Persist verified findings** to `/tmp/batch-final-review-<FIRST-CARD-ID>.md`.
|
|
1563
|
-
11.
|
|
1564
|
-
- **`doc`-domain findings** (file path matching the `doc` match rule
|
|
1565
|
-
- **
|
|
1566
|
-
|
|
1643
|
+
11. **Merge-blocking gate (mirrors the per-card Phase 3.7 gate this final pass backstops):** if any VERIFIED **BLOCKER or HIGH** finding exists, it MUST be resolved before Phase 6 merge. Apply fixes by **domain owner** (since v3.40.0 — same Domain-Override routing as the per-card phases), then re-verify; if a BLOCKER/HIGH cannot be resolved in a single apply + one retry, log it in `## Issues & Flags` and invoke `AskUserQuestion` (override with reason / escalate to a follow-up card / halt) — do NOT proceed to Phase 6 with an unresolved BLOCKER or HIGH. VERIFIED findings of severity MEDIUM are also applied (advisory below that). Partition the verified findings by the **Domain-Override match rules** ("Domain-Override Domains"):
|
|
1644
|
+
- **`doc`-domain findings** (file path matching the `doc` match rule — `*.md` under `${paths.references_dir}`/`${paths.prd_dir}`, `CHANGELOG.md`, `ssot-registry.md`) → invoke the **doc-reviewer** agent once in write mode to apply them. NEVER route doc fixes to coder.
|
|
1645
|
+
- **`security`-domain findings** (path in `paths.high_risk_modules`, or RLS-policy SQL) and **`migration`-domain findings** (SQL under the migrations dir) → route to **coder**, but apply the Sub-agent failure protocol's STOP-on-crash rule for these domains (never inline-fallback on a security/migration fix). These are NOT collapsed into a generic "everything else" bucket.
|
|
1646
|
+
- **All remaining findings** (other code, perf, test) → invoke the **coder** agent once to apply them in a single pass.
|
|
1647
|
+
Run in the order doc-reviewer → coder (or skip either if its partition is empty). Pass only the verified findings, not false positives.
|
|
1567
1648
|
12. Run final build: `npm run lint && npx tsc --noEmit && npm run build`.
|
|
1568
1649
|
If any check fails, apply self-healing retry loop (up to 3 times).
|
|
1569
1650
|
13. **Update tracker** with final review results:
|
|
1570
|
-
- Review engine: Codex
|
|
1651
|
+
- Review engine: Codex (a non-Anthropic frontier model, resolved at runtime by `codex-companion.mjs`) (primary) | Claude code-reviewer (fallback)
|
|
1571
1652
|
- Total findings raised / verified / false positives / needs-manual
|
|
1572
1653
|
- Fixes applied count
|
|
1573
1654
|
- Build status (pass/fail + retry count)
|
|
1574
1655
|
- Highest severity found
|
|
1575
|
-
|
|
1656
|
+
- **Phase-8 producer (named counters)** — ALSO write the structured line `review_findings: total=<R> verified=<V> blockers=<B>` to the tracker `## Final Review` section, where `R` = all findings raised (Codex + Claude agents, pre-FP), `V` = VERIFIED count, `B` = VERIFIED-BLOCKER count. These are the single named producers for Phase 8's batch-level `findings_total` / `findings_verified` / `blockers_count` — Phase 8 reads THESE keys, never re-parses prose. (Per-card Phase 3.7 codex counts stay in `## Pre-Merge Codex Review`; Phase 8 uses the batch-level `review_findings` line here as the canonical total so the QA-findings and codex-findings counts are not conflated.)
|
|
1657
|
+
|
|
1658
|
+
### Step F.6 — Post-review wrap-up (SSOT summary, sync, hand-off to Phase 6)
|
|
1659
|
+
|
|
1660
|
+
> This is a distinct sub-section from F.1–F.5 (its own list); the numbering below restarts and does NOT continue the F.5 counter.
|
|
1661
|
+
|
|
1662
|
+
1. **SSOT & Documentation Activity** (MANDATORY — run BEFORE merge):
|
|
1576
1663
|
|
|
1577
1664
|
Summarize all documentation and SSOT updates performed during the batch:
|
|
1578
1665
|
|
|
@@ -1590,34 +1677,36 @@ Once ALL cards are committed in the worktree:
|
|
|
1590
1677
|
- `${paths.adrs_dir}/ADR-YYYYMMDD-<slug>.md` — [titolo] (o "Nessun ADR creato")
|
|
1591
1678
|
```
|
|
1592
1679
|
|
|
1593
|
-
|
|
1680
|
+
2. **Knowledge Base Sync** (OPTIONAL — only if the project has an external knowledge corpus, e.g. an Obsidian vault, Confluence space, or Notion workspace):
|
|
1594
1681
|
|
|
1595
|
-
If the project ships a `knowledge-sync` agent (
|
|
1682
|
+
If the project ships a `knowledge-sync` corpus agent (declared in `.baldart/overlays/new.md`), invoke it after doc updates so the external corpus stays aligned. If no such agent exists, skip this step with a one-line notice (do NOT dispatch a non-existent agent).
|
|
1596
1683
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1684
|
+
3. **Proceed to Phase 6** (post-batch merge & cleanup).
|
|
1685
|
+
4. Present a **single summary report** to the user per card (and a batch summary at the end):
|
|
1599
1686
|
- **Files changed** (short list per card)
|
|
1600
1687
|
- **Test results** (new tests + existing tests count, pass rate at each iteration)
|
|
1601
1688
|
- **Build/lint status** (pass + retry count if any)
|
|
1602
1689
|
- **Fix cycles** (total number of self-healing retries across phases)
|
|
1603
1690
|
- **Final review** (findings: N raised / M verified / K false positives | fixes applied: N | highest severity)
|
|
1604
1691
|
- **UX testing** (PASS/FAIL/SKIP | test file path if written)
|
|
1605
|
-
- **QA result** (profile: skip/light/balanced/deep | verdict: PASS/FAIL/SKIP | confidence % |
|
|
1692
|
+
- **QA result** (profile: skip/light/balanced/deep | verdict: PASS/FAIL/SKIP | confidence % | failing gates: which of lint/tsc/test/build/markdownlint, or "none" | findings file path). E2E is reported separately (Phase 2.6 e2e-review), not by qa-sentinel.
|
|
1606
1693
|
- **Issues needing user attention** (anything unresolved, partially wired, or flagged)
|
|
1607
1694
|
- **Commit hashes** (from tracker)
|
|
1608
1695
|
- **Merge commit hash** (from Phase 6)
|
|
1609
1696
|
- **Card status reconciliation** (Phase 6b: N cards verified DONE, K force-updated)
|
|
1610
1697
|
- **Worktree cleanup status** (success/failed)
|
|
1611
|
-
- **
|
|
1698
|
+
- **Knowledge-corpus sync status** (from Step F.6 item 2 "Knowledge Base Sync" — COMPLETED/FAILED/PARTIAL, or SKIPPED if no corpus-sync agent is configured)
|
|
1612
1699
|
- Overall implementation status
|
|
1613
1700
|
|
|
1614
|
-
|
|
1701
|
+
4b. **Next Steps & Launch Command** (MANDATORY section — always present):
|
|
1615
1702
|
|
|
1616
|
-
Check for remaining
|
|
1703
|
+
Check for remaining not-yet-DONE cards in the same epic group (match "not DONE",
|
|
1704
|
+
not a hard-coded status value — see the `status enum` SSOT in REGISTRY.md):
|
|
1617
1705
|
|
|
1618
1706
|
```bash
|
|
1619
|
-
# Find parent epic
|
|
1620
|
-
grep -l "parent: <EPIC-ID>"
|
|
1707
|
+
# Find parent epic's cards that are NOT yet DONE (TODO | READY | IN_PROGRESS | BLOCKED)
|
|
1708
|
+
grep -l "parent: <EPIC-ID>" ${paths.backlog_dir}/*.yml \
|
|
1709
|
+
| xargs grep -L "status: DONE"
|
|
1621
1710
|
```
|
|
1622
1711
|
|
|
1623
1712
|
Present the section:
|
|
@@ -1648,10 +1737,10 @@ Once ALL cards are committed in the worktree:
|
|
|
1648
1737
|
## Prossimi Passi
|
|
1649
1738
|
|
|
1650
1739
|
Tutte le card dell'epic **FEAT-XXXX** sono state completate.
|
|
1651
|
-
Pronto per il deploy: `/deploy` o `git push origin
|
|
1740
|
+
Pronto per il deploy: `/deploy` o `git push origin <trunk branch>` (il `git.trunk_branch` configurato)
|
|
1652
1741
|
```
|
|
1653
1742
|
|
|
1654
|
-
|
|
1743
|
+
5. **Proceed to Phase 7** (production readiness checklist).
|
|
1655
1744
|
|
|
1656
1745
|
---
|
|
1657
1746
|
|
|
@@ -1669,10 +1758,10 @@ After the final review passes AND all cards are committed in the worktree, deleg
|
|
|
1669
1758
|
- The worktree path and branch from the tracker
|
|
1670
1759
|
- `checksAlreadyPassed: true` (final review + QA already validated the build)
|
|
1671
1760
|
- All card IDs for the commit message
|
|
1672
|
-
3. The skill handles: safety commit of any remaining uncommitted files (step 3), rebasing onto latest
|
|
1761
|
+
3. The skill handles: safety commit of any remaining uncommitted files (step 3), rebasing onto the latest trunk (`$TRUNK` = `git.trunk_branch`) (step 4b — auto-resolves doc conflicts, stops on code conflicts), merging into the trunk via the configured `git.merge_strategy` (step 4c — `pr` uses `gh pr merge`, `local-push` does a direct FF push to `origin/$TRUNK`; NEITHER runs `git checkout` of the trunk on the main repo, respecting the absolute terminal-isolation rule), post-merge verification, worktree removal, registry cleanup, and remote branch deletion.
|
|
1673
1762
|
4. **If code merge conflicts** → the skill STOPs and reports. Doc-only conflicts (ssot-registry.md, project-status.md, etc.) are auto-resolved by keeping both sides.
|
|
1674
1763
|
5. **If post-merge build fails** → the skill STOPs and keeps the worktree intact for investigation.
|
|
1675
|
-
6. Record the merge commit hash and result in the tracker.
|
|
1764
|
+
6. Record the merge commit hash and result in the tracker. **Also record the merge timestamp** under `## Worktree Merges` (`merge_ts: <ISO-8601>`): for `local-push` use the local merge-commit time (`git log --format=%ci <hash>`); for `pr` (`gh pr merge`) use the PR merge completion time, or note `merge_ts: pending` if GitHub has not yet finalized the merge. Phase 8's `cycle_time_mins` reads THIS field as the strategy-independent end anchor (never a raw hash that may be the PR HEAD).
|
|
1676
1765
|
|
|
1677
1766
|
### Phase 6b — Backlog Card Status Reconciliation (MANDATORY — ZERO TOLERANCE)
|
|
1678
1767
|
|
|
@@ -1739,7 +1828,7 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
|
|
|
1739
1828
|
|
|
1740
1829
|
### Phase 6c — Workspace Hygiene Post-merge (BLOCKING — non-skippable)
|
|
1741
1830
|
|
|
1742
|
-
**Why this exists**: FEAT-0006 incident closed the batch leaving the main repo with an unpushed orphan commit (`c9d41f9`) and local `develop` diverged from `origin/develop` for a manual fix. This phase closes the loop opened by Phase 0: it verifies the main repo is clean and synchronized, parses the `[SYNC-DEFERRED]` marker emitted by `/mw` when HEAD ≠
|
|
1831
|
+
**Why this exists**: FEAT-0006 incident closed the batch leaving the main repo with an unpushed orphan commit (`c9d41f9`) and local `develop` diverged from `origin/develop` for a manual fix. This phase closes the loop opened by Phase 0: it verifies the main repo is clean and synchronized, parses the `[SYNC-DEFERRED]` marker emitted by `/mw` when HEAD ≠ `$TRUNK`, and restores any stash saved in Phase 0.
|
|
1743
1832
|
|
|
1744
1833
|
**Auto Mode does NOT override this phase.** Every `AskUserQuestion` below is non-bypassable.
|
|
1745
1834
|
|
|
@@ -1751,11 +1840,11 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
|
|
|
1751
1840
|
```
|
|
1752
1841
|
|
|
1753
1842
|
2. **Parse `mw-docs` sync markers** — scan the captured stdout from every `/mw` invocation in this batch (kept in the tracker under `## Worktree Merges`):
|
|
1754
|
-
- **`[SYNC-DEFERRED] main repo HEAD=<branch>`** (main repo HEAD ≠
|
|
1755
|
-
- Question: `"Una o più merge worktree hanno deferito la sincronizzazione di local
|
|
1756
|
-
- Options: `[Ora HEAD è
|
|
1757
|
-
- **`[SYNC-NEEDS-DECISION] …`** (HEAD was
|
|
1758
|
-
- Question: `"Il
|
|
1843
|
+
- **`[SYNC-DEFERRED] main repo HEAD=<branch>`** (main repo HEAD ≠ `$TRUNK`) — surface via `AskUserQuestion`:
|
|
1844
|
+
- Question: `"Una o più merge worktree hanno deferito la sincronizzazione di local $TRUNK (main repo HEAD non era $TRUNK). Come riconcilio adesso?"`
|
|
1845
|
+
- Options: `[Ora HEAD è $TRUNK → ff-pull adesso]` / `[Lascia deferred (riconcilio io manualmente)]` / `[Mostra dettagli e fammi decidere]`.
|
|
1846
|
+
- **`[SYNC-NEEDS-DECISION] …`** (HEAD was `$TRUNK` 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`:
|
|
1847
|
+
- Question: `"Il $TRUNK locale non si è sincronizzato: <dettaglio dal marker>. Come chiudo?"`
|
|
1759
1848
|
- Options: `[Committa tu adesso (descrivi cosa)]` / `[Lo gestisco io — chiudi senza sync locale]` / `[Mostrami il diff e decidiamo]`.
|
|
1760
1849
|
- **No marker** — `/mw` fast-forwarded (or auto-reconciled the framework telemetry log); nothing to parse.
|
|
1761
1850
|
|
|
@@ -1767,27 +1856,29 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
|
|
|
1767
1856
|
- Question: `"Main repo ha modifiche non committate dopo il batch (non c'era stash di Phase 0). Cosa faccio?"`
|
|
1768
1857
|
- Options: `[Mostrami il diff e fammi decidere]` / `[Stash adesso con label baldart-post-batch-<timestamp>]` / `[Lascia così (lo gestisco io)]` / `[Halt]`.
|
|
1769
1858
|
|
|
1770
|
-
4. **Divergence assertion (BLOCKING — this catches the FEAT-0006 orphan-commit pattern)
|
|
1859
|
+
4. **Divergence assertion (BLOCKING — this catches the FEAT-0006 orphan-commit pattern)**. `$MAIN` and `$TRUNK` are read from the tracker (`## Worktree` section); HALT if either is absent/empty.
|
|
1771
1860
|
```bash
|
|
1772
|
-
git -C "$MAIN" rev-list --left-right --count origin
|
|
1861
|
+
git -C "$MAIN" rev-list --left-right --count "origin/$TRUNK...$TRUNK"
|
|
1773
1862
|
```
|
|
1774
1863
|
If the output is anything other than `0\t0`:
|
|
1775
1864
|
- **Ahead only (M > 0, unpushed commits)** — invoke `AskUserQuestion`:
|
|
1776
|
-
- Question: `"Local
|
|
1777
|
-
- Options: `[Push adesso (git push origin
|
|
1778
|
-
- On `Reset --hard origin
|
|
1865
|
+
- Question: `"Local $TRUNK ha M commit non pushati su origin/$TRUNK al termine del batch. Lista: <git log --oneline origin/$TRUNK..$TRUNK>. Cosa faccio?"`
|
|
1866
|
+
- Options: `[Push adesso (git push origin $TRUNK)]` / `[Cherry-pick selettivo su origin/$TRUNK]` / `[Reset --hard origin/$TRUNK (richiede conferma esplicita, DISTRUTTIVO)]` / `[Halt con stato preservato]`.
|
|
1867
|
+
- On `Reset --hard origin/$TRUNK` re-ask `AskUserQuestion` to confirm: `"Confermi reset --hard? I commit <list> verranno persi se non pushati altrove."` Solo dopo conferma esplicita esegui il reset.
|
|
1779
1868
|
- **Behind only (N > 0)** — invoke `AskUserQuestion`:
|
|
1780
|
-
- Question: `"Local
|
|
1869
|
+
- Question: `"Local $TRUNK è behind origin/$TRUNK di N commit (qualcuno ha pushato durante il batch). Faccio ff-pull adesso?"`
|
|
1781
1870
|
- Options: `[Fast-forward pull]` / `[Lascia behind (lo gestisco io)]`.
|
|
1782
1871
|
- **Diverged both ways** — invoke `AskUserQuestion`:
|
|
1783
|
-
- Question: `"Local
|
|
1784
|
-
- Options: `[Rebase local
|
|
1872
|
+
- Question: `"Local $TRUNK è diverged (N behind, M ahead). Servono entrambe le riconciliazioni. Come procedo?"`
|
|
1873
|
+
- Options: `[Rebase local $TRUNK su origin/$TRUNK]` / `[Mostrami i commit locali e decidiamo]` / `[Halt]`.
|
|
1785
1874
|
|
|
1786
|
-
5. **Restore Phase 0 stash (if any)** — read the tracker for `## Workspace Snapshot: <
|
|
1787
|
-
- If
|
|
1788
|
-
- If
|
|
1875
|
+
5. **Restore Phase 0 stash (if any)** — read the tracker for `## Workspace Snapshot: <message-label>`:
|
|
1876
|
+
- If the snapshot is `dirty-tree override` → skip restore, log "user retained dirty-tree responsibility".
|
|
1877
|
+
- If it is a stash MESSAGE label (e.g. `baldart-new-phase0-<FIRST-CARD-ID>-<timestamp>`) — resolve the stash by its message, NEVER by positional `stash@{N}` (other stashes may have shifted the index since Phase 0). This runs on `$MAIN` (the main checkout, not a worktree), so a stash op here is safe:
|
|
1789
1878
|
```bash
|
|
1790
|
-
git -C "$MAIN" stash
|
|
1879
|
+
REF="$(git -C "$MAIN" stash list | grep -F "<message-label>" | head -1 | cut -d: -f1)"
|
|
1880
|
+
[ -n "$REF" ] && git -C "$MAIN" stash pop "$REF" \
|
|
1881
|
+
|| echo "stash '<message-label>' not found — was it already restored?"
|
|
1791
1882
|
```
|
|
1792
1883
|
On conflict, do NOT silent-drop — invoke `AskUserQuestion`:
|
|
1793
1884
|
- Question: `"Restore dello stash di Phase 0 ha generato conflitti. Lo stash è ancora presente (NON eliminato). Come procedo?"`
|
|
@@ -1798,7 +1889,7 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
|
|
|
1798
1889
|
## Phase 6c — Workspace Hygiene Post-merge
|
|
1799
1890
|
Status: PASS
|
|
1800
1891
|
Clean-tree: <yes | resolved: stashed | user-retained>
|
|
1801
|
-
Divergence (local…origin
|
|
1892
|
+
Divergence (local…origin/$TRUNK): <0\t0 | resolved: pushed/cherry-picked/ff-pulled/rebased>
|
|
1802
1893
|
Sync-deferred markers: <none | reconciled | user-retained>
|
|
1803
1894
|
Phase 0 snapshot restore: <n/a | popped clean | conflict-deferred-to-user>
|
|
1804
1895
|
Completed: <timestamp>
|
|
@@ -1808,11 +1899,11 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
|
|
|
1808
1899
|
7. **Anti-bypass guard** — like Phase 0, before exiting Phase 6c re-read the tracker section you just wrote. Missing `## Phase 6c` → refuse to proceed to Phase 7. There is no `--skip-phase-6c` flag; treat any urge to skip as a self-correction trigger.
|
|
1809
1900
|
|
|
1810
1901
|
### Fail-safe rules (enforced by worktree-manager skill)
|
|
1811
|
-
- **Never `git checkout`, `git switch`, `git checkout -b`, or `git branch` on the main repo** from inside this orchestrator. The main repo is shared across parallel terminals. Use the configured `git.merge_strategy` for
|
|
1812
|
-
- Never merge
|
|
1813
|
-
- Never force push to
|
|
1902
|
+
- **Never `git checkout`, `git switch`, `git checkout -b`, or `git branch` on the main repo** from inside this orchestrator. The main repo is shared across parallel terminals. Use the configured `git.merge_strategy` for trunk merges and `git -C <main> pull --ff-only` (only when `HEAD = $TRUNK` already) for sync. See `/mw` step 4c.
|
|
1903
|
+
- Never merge into a release/production branch — only into the integration trunk (`$TRUNK` = `git.trunk_branch`), via the configured `git.merge_strategy` (NOT local checkout).
|
|
1904
|
+
- Never force push to the trunk. `--force-with-lease` on feature branches after rebase is allowed.
|
|
1814
1905
|
- Never delete a branch before successful merge verification.
|
|
1815
|
-
- Never remove a worktree before confirming
|
|
1906
|
+
- Never remove a worktree before confirming the trunk is stable post-merge.
|
|
1816
1907
|
- Stop execution immediately if any command fails.
|
|
1817
1908
|
|
|
1818
1909
|
---
|
|
@@ -2067,7 +2158,7 @@ If at ANY point you are unsure where you are in the batch:
|
|
|
2067
2158
|
|
|
2068
2159
|
### Team mode (for complex batches)
|
|
2069
2160
|
|
|
2070
|
-
- Cards within the same `
|
|
2161
|
+
- Cards within the same `execution_strategy.groups` level (same `level`) run in parallel via isolated coder agents.
|
|
2071
2162
|
- Groups execute sequentially (group 0 → group 1 → group 2...).
|
|
2072
2163
|
- Review + QA run ONCE per group (combined), not per card.
|
|
2073
2164
|
- The orchestrator holds ONLY coordination state, never implementation details.
|
|
@@ -2097,7 +2188,7 @@ It does NOT accumulate implementation details, codebase-architect findings, or r
|
|
|
2097
2188
|
|
|
2098
2189
|
After the standard pre-flight (steps 1-7), add:
|
|
2099
2190
|
|
|
2100
|
-
1. Read
|
|
2191
|
+
1. Read the `execution_strategy.groups` (each with `level` + `cards`) and sort into execution layers by `level`. For legacy cards lacking the block, fall back to the on-the-fly topological-layer computation from step 3c.
|
|
2101
2192
|
2. Update tracker with team mode section:
|
|
2102
2193
|
```
|
|
2103
2194
|
## Team Mode
|
|
@@ -2191,16 +2282,17 @@ Agent tool call:
|
|
|
2191
2282
|
### 7. Completion Report (MANDATORY)
|
|
2192
2283
|
```completion-report
|
|
2193
2284
|
card: <CARD-ID>
|
|
2194
|
-
status: done | partial |
|
|
2285
|
+
status: done | partial | blocked # card-level — matches coder.md four-state (coder never self-emits deferred-approved; the orchestrator sets that after the AC-Closure Gate)
|
|
2195
2286
|
requirements:
|
|
2196
2287
|
- id: 1
|
|
2197
2288
|
text: "[text]"
|
|
2198
|
-
status: done | partial
|
|
2289
|
+
status: done | not_implemented # per-requirement is BINARY (legacy row-level partial/blocked were silent-deferral channels — removed)
|
|
2199
2290
|
evidence: "file:line"
|
|
2200
2291
|
files_changed:
|
|
2201
2292
|
- path/to/file.ts
|
|
2202
2293
|
build_status: pass | fail
|
|
2203
2294
|
lint_status: pass | fail
|
|
2295
|
+
tsc_status: pass | fail | n/a # n/a when stack.language excludes typescript
|
|
2204
2296
|
retry_count: N
|
|
2205
2297
|
```
|
|
2206
2298
|
```
|
|
@@ -2214,10 +2306,11 @@ For each completed agent:
|
|
|
2214
2306
|
2. Log to tracker: card ID, status, files changed, build/lint status.
|
|
2215
2307
|
3. Do NOT read or store implementation details — only the verdict.
|
|
2216
2308
|
|
|
2217
|
-
**If an agent fails** (status: failed after 3 retries):
|
|
2309
|
+
**If an agent fails** (status: failed after 3 retries — the central repair cap):
|
|
2218
2310
|
- Log failure in tracker `## Issues & Flags`.
|
|
2219
2311
|
- Other agents in the group continue unaffected.
|
|
2220
2312
|
- After group completes, ask user: retry failed card or skip?
|
|
2313
|
+
- **Retry re-entry (defined path):** on "retry", re-run the failed card from **Step B** (re-spawn the autonomous coder with a fresh briefing) — NOT from Step A, because the Step A arch context for the group is already in hand and is reused. The retried card then rejoins the group's Step D pipeline and MUST pass the SAME mandatory per-card sub-steps as its peers (D.3a AC-Closure → D.3b Simplify → D.3c E2E → D.4 QA → D.4a doc → D.4b codex → D.5 commit → D.6 backlog); there is no shortcut. The Step D coverage assertion will block Step E until the retried card has all mandatory tracker entries — so a retried card cannot silently skip a gate. **Cap: one Step-B re-entry per card** (consistent with the central cap discipline); on a second failure, re-ask with only skip/abandon so the loop cannot recur unbounded.
|
|
2221
2314
|
|
|
2222
2315
|
#### Step D: Post-group review + QA (ALL sub-steps MANDATORY)
|
|
2223
2316
|
|
|
@@ -2235,21 +2328,27 @@ After ALL agents in the group complete successfully:
|
|
|
2235
2328
|
|
|
2236
2329
|
3b. **D.3b — Phase 2.55 Simplify (per-card)** — For EACH card in the group, invoke Phase 2.55 (Reuse / Quality / Efficiency parallel agents) on the per-card diff (`git diff --name-only` filtered by the card's File Ownership Map). Per-card (not group-aggregate) so findings are attributable. Apply fixes inline. After all cards: re-run `npm run lint` and `npx tsc --noEmit` on the worktree once.
|
|
2237
2330
|
|
|
2238
|
-
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.
|
|
2331
|
+
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 in the Phase 2.6 skip set — `backend`/`api`/`db`/`infra`/`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.
|
|
2239
2332
|
|
|
2240
|
-
4. **D.4 — QA gate (group)** — Read each card's `review_profile` field (fallback: compute via the QA Profile Selector
|
|
2333
|
+
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.
|
|
2241
2334
|
|
|
2242
|
-
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>`.
|
|
2335
|
+
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.
|
|
2243
2336
|
|
|
2244
|
-
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-
|
|
2337
|
+
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 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: 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.
|
|
2245
2338
|
|
|
2246
2339
|
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):
|
|
2247
2340
|
```bash
|
|
2248
2341
|
cd <worktree-path>
|
|
2249
2342
|
# For each card in the group:
|
|
2250
2343
|
git add <card's-files-only>
|
|
2251
|
-
|
|
2344
|
+
# Disambiguate "nothing to commit" from a hook rejection BEFORE committing:
|
|
2345
|
+
if [ -z "$(git status --porcelain)" ]; then
|
|
2346
|
+
echo "D.5 <CARD-ID>: nothing staged — already committed upstream; record HEAD and skip"
|
|
2347
|
+
else
|
|
2348
|
+
git commit -m "[CARD-ID] Brief description"
|
|
2349
|
+
fi
|
|
2252
2350
|
```
|
|
2351
|
+
If `git commit` itself fails with a non-empty staging area (a pre-commit / lint-staged hook rejected it), apply the SAME bounded handler as sequential Phase 4 step 27: clear a stale `COMMIT_LOCK`, re-stage explicitly, retry at most **2 times**, then log `[COMMIT-BLOCKED]` and escalate via `AskUserQuestion` — never loop unbounded and never silently leave a card uncommitted.
|
|
2253
2352
|
|
|
2254
2353
|
6. **D.6 — Update backlog (MANDATORY — do NOT skip)** — For EACH card in the group:
|
|
2255
2354
|
a. Edit the backlog YAML (`${paths.backlog_dir}/<CARD-ID>.yml`): set `status: DONE`, add `completed_date: <today>`, add implementation notes (NEVER include `[USER-APPROVED DEFERRAL]` lines that didn't actually pass through D.3a's gate).
|
|
@@ -2297,42 +2396,54 @@ After all groups are complete, run the same Final Review, Phase 6 (merge), and P
|
|
|
2297
2396
|
|
|
2298
2397
|
---
|
|
2299
2398
|
|
|
2300
|
-
## Phase 8 — Metrics Log (
|
|
2399
|
+
## Phase 8 — Metrics Log (MONITORING SIGNAL — non-blocking — runs after Phase 7)
|
|
2301
2400
|
|
|
2302
2401
|
After the Production Readiness Checklist is complete, log this batch run to the skill
|
|
2303
2402
|
effectiveness registry. This enables tracking of first-attempt success rate, actionability,
|
|
2304
|
-
and QA quality over time.
|
|
2403
|
+
and QA quality over time. This is a telemetry write, NOT a gate — it never blocks the batch (see
|
|
2404
|
+
the fail-safe note at the end of the phase). It was previously labelled "MANDATORY", but since it
|
|
2405
|
+
has no blocking consequence the honest label is "monitoring signal".
|
|
2305
2406
|
|
|
2306
2407
|
**Steps:**
|
|
2307
2408
|
|
|
2308
|
-
1. Read the batch tracker file (`/tmp/batch-tracker-<FIRST-CARD-ID>.md`) to extract:
|
|
2409
|
+
1. Read the batch tracker file (`/tmp/batch-tracker-<FIRST-CARD-ID>.md`) to extract — every field below has a NAMED upstream producer; read the structured key, do NOT re-parse prose:
|
|
2309
2410
|
- Start timestamp (from `Started:` field)
|
|
2411
|
+
- Worktree-creation timestamp (from `## Worktree` — the time Phase 0/Pre-flight created the worktree; the strategy-independent cycle-time anchor, see step 2)
|
|
2310
2412
|
- Card list and total count
|
|
2311
|
-
- For each completed card:
|
|
2312
|
-
|
|
2413
|
+
- For each completed card:
|
|
2414
|
+
- `fix_cycles` (from the per-phase retry counts logged in `## Completed Cards`)
|
|
2415
|
+
- `qa_profile`, `qa_verdict` (Phase 3.5 step 25 / D.4 QA line)
|
|
2416
|
+
- `qa_first_attempt` (Phase 3.5 step 25 named flag — `pass`/`fail`/`n/a`)
|
|
2417
|
+
- `doc_gaps: found=<N> fixed=<M>` (Phase 3 step 15 / D.4a named counter)
|
|
2418
|
+
- Batch-level `review_findings: total / verified / blockers` (Final Review F.5 step 13 named counters — the canonical source for `findings_total` / `findings_verified` / `blockers_count`)
|
|
2419
|
+
- Merge commit hash (and, when `git.merge_strategy: pr`, the PR merge timestamp recorded by Phase 6 — see step 2)
|
|
2420
|
+
|
|
2421
|
+
If any named field is absent (e.g. a legacy tracker), record `0`/`n/a` for that field and append `metrics_gaps: <field>` to the JSONL row's notes — do NOT invent a value by re-parsing free-form prose.
|
|
2313
2422
|
|
|
2314
2423
|
2. Compute aggregate metrics:
|
|
2315
2424
|
- `first_attempt_success_rate`: cards with fix_cycles == 0 / total_cards
|
|
2316
2425
|
- `mean_fix_cycles`: mean of per-card fix cycle counts
|
|
2317
2426
|
- `qa_profiles`: count of {skip, light, balanced, deep}
|
|
2318
|
-
- `qa_pass_first_attempt_rate`: cards with
|
|
2319
|
-
- `findings_total` / `findings_verified`: sum
|
|
2320
|
-
- `actionability_rate`: findings_verified / findings_total (conservative proxy; 0 if no findings)
|
|
2427
|
+
- `qa_pass_first_attempt_rate`: cards with `qa_first_attempt == pass` / cards where qa ran (exclude `n/a` SKIP/LIGHT cards from the denominator) — read the named flag from step 1, do NOT re-infer from `## Fix Application Log` rows
|
|
2428
|
+
- `findings_total` / `findings_verified`: from the batch-level `review_findings` named counter (Final Review), NOT a per-card re-sum (which would conflate QA gate counts with codex review findings)
|
|
2429
|
+
- `actionability_rate`: findings_verified / findings_total (conservative proxy — a lower-bound on reviewer precision, since some VERIFIED findings end as NEEDS_MANUAL_CONFIRMATION and never produce a fix; 0 if no findings)
|
|
2321
2430
|
- `severity_p0_pct`: blockers_count / findings_total (0 if no findings)
|
|
2322
|
-
- `cycle_time_mins`: minutes from `Started:`
|
|
2431
|
+
- `cycle_time_mins`: minutes from the **strategy-independent anchor** to batch completion. Use the **worktree-creation timestamp** (Phase 0/Pre-flight) as the start, NOT `Started:` (which precedes workspace hygiene) and NOT a merge-commit hash (which varies by `git.merge_strategy` — under `pr` the merge commit is created asynchronously by GitHub CI and may not exist locally at Phase 8 time). End anchor: read the `merge_ts` field Phase 6 step 6 recorded under `## Worktree Merges` (it is already strategy-resolved there — local merge-commit time for `local-push`, PR merge completion time for `pr`). If `merge_ts: pending` (a `pr` merge GitHub has not yet finalized), fall back to "now" (`date -u`). Never recompute from a raw merge-commit hash that may be the PR HEAD rather than the actual merge commit.
|
|
2432
|
+
|
|
2433
|
+
> `$METRICS` = `paths.metrics` from `baldart.config.yml` (default `docs/metrics`). All paths below resolve under `$METRICS` — never a hardcoded `docs/metrics`.
|
|
2323
2434
|
|
|
2324
|
-
3.
|
|
2435
|
+
3. **Assemble the full JSONL record in memory** (single atomic append — JSONL is append-only, so the row must be COMPLETE before it touches the file). If `STATS=true` (step 6), the `"cost"` key is part of THIS record — do NOT write a baseline row now and rewrite it later (a mid-file rewrite corrupts the JSONL; there is no `sed -i`/`jq` rewrite step in this skill). When `STATS=true`, defer the single append to step 6 after the cost object is computed; when `STATS=false`, append now. The record shape:
|
|
2325
2436
|
|
|
2326
2437
|
```json
|
|
2327
2438
|
{"ts":"<ISO-8601-UTC>","skill":"new","run_id":"batch-<FIRST-CARD-ID>","cards":["FEAT-XXX"],"total_cards":N,"first_attempt_success_rate":0.0,"mean_fix_cycles":0.0,"qa_profiles":{"skip":0,"light":0,"balanced":0,"deep":0},"qa_pass_first_attempt_rate":0.0,"findings_total":0,"findings_verified":0,"actionability_rate":0.0,"severity_p0_pct":0.0,"doc_gaps_found":0,"doc_gaps_fixed":0,"cycle_time_mins":0,"worktree_branch":"","merge_commit":""}
|
|
2328
2439
|
```
|
|
2329
2440
|
|
|
2330
|
-
Use `date -u +%Y-%m-%dT%H:%M:%SZ` for the timestamp.
|
|
2441
|
+
Use `date -u +%Y-%m-%dT%H:%M:%SZ` for the timestamp. Append the assembled line ONCE with `echo '<full-record>' >> "$METRICS/skill-runs.jsonl"` via Bash — never append a partial row then mutate it.
|
|
2331
2442
|
|
|
2332
2443
|
4. Copy the batch tracker to archive:
|
|
2333
2444
|
|
|
2334
2445
|
```bash
|
|
2335
|
-
cp /tmp/batch-tracker-<FIRST-CARD-ID>.md
|
|
2446
|
+
cp /tmp/batch-tracker-<FIRST-CARD-ID>.md "$METRICS/archive/"
|
|
2336
2447
|
```
|
|
2337
2448
|
|
|
2338
2449
|
5. Note in tracker: `## Metrics Log: WRITTEN (run_id: batch-<FIRST-CARD-ID>)`
|
|
@@ -2343,13 +2454,13 @@ and QA quality over time.
|
|
|
2343
2454
|
|
|
2344
2455
|
```bash
|
|
2345
2456
|
node .framework/framework/scripts/analyze-session-tokens.js \
|
|
2346
|
-
--skill new --run-id "batch-<FIRST-CARD-ID>" --out-dir
|
|
2457
|
+
--skill new --run-id "batch-<FIRST-CARD-ID>" --out-dir "$METRICS"
|
|
2347
2458
|
```
|
|
2348
2459
|
|
|
2349
|
-
The script reads `$CLAUDE_CODE_SESSION_ID` from the environment and derives the transcript paths itself (do NOT pass `--session` / `--project-dir` — those are test-only overrides). It writes a human-readable breakdown to
|
|
2460
|
+
The script reads `$CLAUDE_CODE_SESSION_ID` from the environment and derives the transcript paths itself (do NOT pass `--session` / `--project-dir` — those are test-only overrides). It writes a human-readable breakdown to `$METRICS/sessions/batch-<FIRST-CARD-ID>.md` and prints a summary plus a final `TELEMETRY_JSON=<json>` line.
|
|
2350
2461
|
|
|
2351
|
-
Parse the `TELEMETRY_JSON=` line and
|
|
2462
|
+
Parse the `TELEMETRY_JSON=` line and add a `"cost"` key (holding that JSON object: `by_role` + `totals` + `run_wall_ms`) to the in-memory record from step 3, then **append the complete record ONCE** to `$METRICS/skill-runs.jsonl` (this is the deferred single atomic append from step 3 — there is NO already-written row to rewrite, so JSONL semantics stay intact: exactly one line per `run_id`). If the script printed `stats: SKIPPED (...)` instead, set `"cost":{"skipped":"<reason>"}` and append the single record. Echo the script's summary to the user so they see the per-role breakdown.
|
|
2352
2463
|
|
|
2353
|
-
**If
|
|
2464
|
+
**If `$METRICS/skill-runs.jsonl` does not exist**: create it first with `mkdir -p "$METRICS" && touch "$METRICS/skill-runs.jsonl"`.
|
|
2354
2465
|
**If batch tracker is missing or unreadable**: log "Metrics Log: SKIPPED (tracker not found)" and proceed without blocking.
|
|
2355
2466
|
**This phase is NON-BLOCKING** — if it fails for any reason, do not abort the run. The `-stats` step in particular is best-effort: the script is fail-safe (always exits 0), so never let it block the commit.
|