baldart 4.12.0 → 4.13.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 +25 -0
- package/VERSION +1 -1
- package/framework/.claude/agents/coder.md +3 -3
- package/framework/.claude/skills/new/SKILL.md +151 -2356
- package/framework/.claude/skills/new/references/codex-gate.md +129 -0
- package/framework/.claude/skills/new/references/commit.md +57 -0
- package/framework/.claude/skills/new/references/completeness.md +284 -0
- package/framework/.claude/skills/new/references/final-review.md +267 -0
- package/framework/.claude/skills/new/references/implement.md +353 -0
- package/framework/.claude/skills/new/references/merge-cleanup.md +175 -0
- package/framework/.claude/skills/new/references/metrics.md +72 -0
- package/framework/.claude/skills/new/references/production-readiness.md +232 -0
- package/framework/.claude/skills/new/references/review-cycle.md +247 -0
- package/framework/.claude/skills/new/references/setup.md +249 -0
- package/framework/.claude/skills/new/references/team-mode.md +253 -0
- package/framework/.claude/skills/worktree-manager/SKILL.md +16 -8
- package/framework/agents/coding-standards.md +5 -5
- package/package.json +1 -1
|
@@ -114,7 +114,7 @@ Trunk branch: [resolved git.trunk_branch — Phase 0 step 0 populates]
|
|
|
114
114
|
|
|
115
115
|
### Update rules
|
|
116
116
|
|
|
117
|
-
- **Before starting a card**: move it to `## Current Card` with phase info.
|
|
117
|
+
- **Before starting a card**: move it to `## Current Card` with phase info, and record `phase_module_loaded: <modulo>` as you Read each phase module (per § "Routing" HARD RULE) so context recovery can re-load it.
|
|
118
118
|
- **After each phase**: update the current card's phase status in the tracker.
|
|
119
119
|
- **After completing a card**: move it from `Current Card` to `## Completed Cards` with:
|
|
120
120
|
- Commit hash
|
|
@@ -237,239 +237,127 @@ baselines. Keep that bulk on disk and pass **paths**, not bodies.
|
|
|
237
237
|
|
|
238
238
|
---
|
|
239
239
|
|
|
240
|
-
## Phase 0 — Workspace Hygiene Pre-flight (BLOCKING — non-skippable)
|
|
241
240
|
|
|
242
|
-
|
|
241
|
+
## Routing — il per-card pipeline e i moduli on-demand
|
|
242
|
+
|
|
243
|
+
`/new` è uno **orchestrator long-lived**: il suo corpo skill sta nel prefisso di
|
|
244
|
+
sistema, ri-letto a OGNI turno. Per non pagare 60k+ token di istruzioni di fase a
|
|
245
|
+
ogni turno, il dettaglio passo-passo di ogni fase vive in un **modulo `references/<x>.md`**
|
|
246
|
+
caricato on-demand. Questo file (il core) tiene solo gli invarianti cross-fase
|
|
247
|
+
(Context Tracking, Progress Visibility, § "Context economy", Agent Routing, QA
|
|
248
|
+
Profile, Trivial fast-lane, Risk-signal detector, Fix Application Log) + questa
|
|
249
|
+
mappa di navigazione.
|
|
250
|
+
|
|
251
|
+
> **HARD RULE — leggi il modulo PRIMA di eseguire la fase.** Quando entri in una
|
|
252
|
+
> fase, **Read** il suo modulo `references/<x>.md` e poi eseguilo. Eseguire una
|
|
253
|
+
> fase "a memoria" (senza aver caricato il modulo in questo run, o dopo una
|
|
254
|
+
> compaction che l'ha evacuato) è una violazione di protocollo: ricaricalo. Registra
|
|
255
|
+
> nel tracker, sotto `## Current Card`, il campo `phase_module_loaded: <modulo>` al
|
|
256
|
+
> caricamento, così la § "Context recovery protocol" sa cosa ri-leggere dopo una
|
|
257
|
+
> compaction. I `§ "..."` citati dai moduli (Context economy, Context Tracking,
|
|
258
|
+
> Trivial-card fast-lane, Risk-signal detector, Fix Application Log) puntano a sezioni
|
|
259
|
+
> che vivono **qui nel core** → risolvono sempre.
|
|
260
|
+
|
|
261
|
+
**Sequenza (per ogni card, in ordine — i moduli per-card sono caricati per traversata):**
|
|
262
|
+
|
|
263
|
+
| Fase | Quando | Modulo | Skip se (ragione enumerata) |
|
|
264
|
+
|------|--------|--------|------------------------------|
|
|
265
|
+
| 0 — Workspace Hygiene + Pre-flight | a inizio batch (una volta) | [`references/setup.md`](references/setup.md) | mai (BLOCKING) |
|
|
266
|
+
| 1-2 — Claim & Context + Implement | per card | [`references/implement.md`](references/implement.md) | — |
|
|
267
|
+
| 2.5 / 2.5b — Completeness + AC-Closure | dopo l'impl | [`references/completeness.md`](references/completeness.md) | — (2.5b è BLOCKING, mai skip) |
|
|
268
|
+
| 2.55 / 2.6 / 3 / 3.5 — Simplify + E2E + Doc + QA | dopo AC-Closure | [`references/review-cycle.md`](references/review-cycle.md) | `IS_TRIVIAL`→skip 2.55+3.5; `has_e2e_review:false`/backend-only→skip 2.6; `light`+no-doc-diff→Doc a Final; `balanced`→QA a Final |
|
|
269
|
+
| 3.7 — Pre-Merge Codex Review Gate | pre-commit | [`references/codex-gate.md`](references/codex-gate.md) | solo `IS_TRIVIAL` (altrimenti unconditional; `light`/`full` è DEPTH, non skip) |
|
|
270
|
+
| 4-5 — Commit + Context Clean | fine card | [`references/commit.md`](references/commit.md) | — |
|
|
271
|
+
| Final review F.1-F.6 | dopo l'ultima card | [`references/final-review.md`](references/final-review.md) | mai (FULL gate unconditional) |
|
|
272
|
+
| 6 / 6b / 6c — Merge & cleanup | dopo Final | [`references/merge-cleanup.md`](references/merge-cleanup.md) | mai (BLOCKING) |
|
|
273
|
+
| 7 — Production Readiness | dopo il merge | [`references/production-readiness.md`](references/production-readiness.md) | — |
|
|
274
|
+
| 8 — Metrics Log | ultimo | [`references/metrics.md`](references/metrics.md) | mai (non-blocking, best-effort) |
|
|
275
|
+
|
|
276
|
+
**Team Mode** (batch complessi, deciso in Pre-flight per § "Parallelism rules"): il
|
|
277
|
+
per-card pipeline sopra è rimpiazzato dall'esecuzione per-gruppo parallela —
|
|
278
|
+
[`references/team-mode.md`](references/team-mode.md). Le stesse fasi/gate sono propagate
|
|
279
|
+
per-card nei sub-step D.x (mai aggregate). Caricalo quando Pre-flight seleziona team mode.
|
|
243
280
|
|
|
244
|
-
|
|
281
|
+
---
|
|
245
282
|
|
|
246
|
-
|
|
283
|
+
## Parallelism rules
|
|
247
284
|
|
|
248
|
-
|
|
249
|
-
- 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.
|
|
250
|
-
- Resolve `$TRUNK` = `git.trunk_branch` from `baldart.config.yml`. **When the key is absent** (consumer updated to ≥4.0.0 without re-running `configure`), do NOT hard-assume `develop` — autodetect the repo's real default branch exactly as worktree-manager does, so `/new` and `nw` agree on the base: `git -C "$MAIN" symbolic-ref --quiet refs/remotes/origin/HEAD` (strip `refs/remotes/origin/`), else the first existing local branch among `develop` / `main` / `master`. A `main`-trunk repo defaulted to `develop` here would diverge from the worktree base `nw` picks and break every `git diff "$TRUNK...HEAD"` gate. Only HALT ("Trunk branch unresolved — run `npx baldart configure`") if nothing resolves. Persist the resolved value as `Trunk branch:` in the tracker `## Worktree` section. **Every later Phase 0 / Phase 6c bash snippet that references the integration trunk MUST use `$TRUNK`, never a baked-in `develop`.** Begin every later consumer with a guard: if `$TRUNK` is empty → HALT with "Trunk branch unresolved — re-read `git.trunk_branch` from the tracker".
|
|
251
|
-
- Resolve `$METRICS` = `paths.metrics` from `baldart.config.yml` (default `docs/metrics`). This is the framework-owned telemetry directory written by Phase 8 (tracker archive, `skill-runs.jsonl`, `sessions/`). The dirty-tree gate (step 3) reads `$METRICS` to recognise — and never surface — its own telemetry output. Persist it as `Metrics dir:` in the tracker `## Worktree` section.
|
|
285
|
+
### Sequential mode (default for small batches)
|
|
252
286
|
|
|
253
|
-
|
|
287
|
+
- Cards execute one at a time through the full per-card pipeline (Phases 1-5).
|
|
288
|
+
- Code review and doc review for the same card run as **parallel read-only audits**, then fixes are applied by domain owner: **doc findings → `doc-reviewer` (write mode)**, code/security/migration findings → `coder`. (Sequential Phase 3 is even simpler — doc-reviewer runs alone, so it audits AND applies in one invocation.)
|
|
289
|
+
- This mode is unchanged from the original behavior.
|
|
254
290
|
|
|
255
|
-
|
|
256
|
-
```bash
|
|
257
|
-
git -C "$MAIN" fetch origin --quiet
|
|
258
|
-
```
|
|
291
|
+
### Team mode (for complex batches)
|
|
259
292
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
| grep -vE "^.{3}\"?${METRICS}\"?$" \
|
|
269
|
-
| grep -v '^[[:space:]]*$')"
|
|
270
|
-
```
|
|
271
|
-
**Why**: Phase 8 copies the batch tracker into `$METRICS/archive/` and appends to `$METRICS/skill-runs.jsonl` *after* the merge, and never commits them. If those untracked telemetry files tripped this gate, **every batch would block on the previous batch's metrics** — a self-inflicted loop. They are not user work and the user is never asked about them.
|
|
272
|
-
- If `$PORCELAIN` is non-empty but `$USER_DIRTY` is **empty** (only telemetry under `$METRICS` is dirty) → do **NOT** gate. Write `Dirty: framework-telemetry-only (auto-ignored)` to the tracker and proceed to step 4. No `AskUserQuestion`.
|
|
273
|
-
- If `$USER_DIRTY` is **non-empty** (genuine uncommitted user work) → invoke `AskUserQuestion`:
|
|
274
|
-
- Question: `"Main repo ($MAIN) ha modifiche non committate prima di partire con la batch. Come procedo?"`
|
|
275
|
-
- Options (max 4):
|
|
276
|
-
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}`.
|
|
277
|
-
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.
|
|
278
|
-
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.
|
|
279
|
-
4. **"Abort batch"** — halt the batch, leave the tracker file in place, exit.
|
|
280
|
-
|
|
281
|
-
Do NOT silently proceed. Do NOT auto-stash without the user picking option 1.
|
|
282
|
-
|
|
283
|
-
4. **Divergence gate (BLOCKING — framework-management commits do NOT count as orphan commits)** — compare local `$TRUNK` against `origin/$TRUNK` (the trunk resolved in step 0):
|
|
284
|
-
```bash
|
|
285
|
-
read BEHIND AHEAD <<< "$(git -C "$MAIN" rev-list --left-right --count "origin/$TRUNK...$TRUNK")"
|
|
286
|
-
```
|
|
287
|
-
`$BEHIND` / `$AHEAD` are the raw counts. Before branching, **reclassify the ahead commits**: commits produced by `baldart update`/`baldart add` (subtree merges into `.framework/`, the `[CHORE] baldart update …` commit, and the regenerated overlay files they carry) are *expected* divergence, not the FEAT-0006 orphan-commit pattern. Count only **genuine** unpushed commits:
|
|
288
|
-
```bash
|
|
289
|
-
GENUINE_AHEAD=0; GENUINE_LIST=""; FW_SKIPPED=0
|
|
290
|
-
for sha in $(git -C "$MAIN" rev-list "origin/$TRUNK..$TRUNK"); do
|
|
291
|
-
subj="$(git -C "$MAIN" log -1 --format=%s "$sha")"
|
|
292
|
-
# subtree merge (e.g. "Merge commit '…' as '.framework'") or baldart update/add chore
|
|
293
|
-
if printf '%s' "$subj" | grep -qE "as '\.framework'" || printf '%s' "$subj" | grep -qiE "baldart (update|add)"; then
|
|
294
|
-
FW_SKIPPED=$((FW_SKIPPED+1)); continue
|
|
295
|
-
fi
|
|
296
|
-
# touches ONLY files under .framework/ ? (empty file list = merge commit, handled above)
|
|
297
|
-
files="$(git -C "$MAIN" show --pretty=format: --name-only "$sha" | grep -v '^$')"
|
|
298
|
-
if [ -n "$files" ] && ! printf '%s\n' "$files" | grep -qvE '^\.framework/'; then
|
|
299
|
-
FW_SKIPPED=$((FW_SKIPPED+1)); continue
|
|
300
|
-
fi
|
|
301
|
-
GENUINE_AHEAD=$((GENUINE_AHEAD+1)); GENUINE_LIST="$GENUINE_LIST $sha"
|
|
302
|
-
done
|
|
303
|
-
```
|
|
304
|
-
`$FW_SKIPPED` framework-management commits are auto-ignored (log them — see below). Branch on `$BEHIND` and the **genuine** ahead count `$GENUINE_AHEAD` (NOT the raw `$AHEAD`):
|
|
305
|
-
|
|
306
|
-
- **`BEHIND=0` and `GENUINE_AHEAD=0`** — synchronized for `/new`'s purposes. If `$FW_SKIPPED > 0`, write `Divergence: $FW_SKIPPED framework-management commits ahead (auto-ignored — baldart update/subtree)` to the tracker. **No `AskUserQuestion`.** Proceed to step 5.
|
|
307
|
-
- **`BEHIND>0` and `GENUINE_AHEAD=0`** (only behind) — invoke `AskUserQuestion`:
|
|
308
|
-
- Question: `"Local $TRUNK è behind origin/$TRUNK di $BEHIND commit. Come procedo?"`
|
|
309
|
-
- Options: `[Fast-forward pull adesso]` / `[Procedi senza pull]` / `[Abort]`.
|
|
310
|
-
- 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".
|
|
311
|
-
- **`BEHIND=0` and `GENUINE_AHEAD>0`** (genuine UNPUSHED LOCAL COMMITS, this is the FEAT-0006 pattern) — invoke `AskUserQuestion`:
|
|
312
|
-
- Question: `"Local $TRUNK è ahead di origin/$TRUNK di $GENUINE_AHEAD commit locali non pushati (esclusi $FW_SKIPPED commit di gestione framework). Cosa faccio?"`
|
|
313
|
-
- Show **only the genuine** commits inline: `git -C "$MAIN" show -s --oneline $GENUINE_LIST`.
|
|
314
|
-
- Options: `[Push adesso (git push origin $TRUNK)]` / `[Cherry-pick a parte e continua]` / `[Lascia così e procedi (lo gestisco io)]` / `[Abort]`.
|
|
315
|
-
- **`BEHIND>0` and `GENUINE_AHEAD>0`** (diverged both ways) — invoke `AskUserQuestion`:
|
|
316
|
-
- Question: `"Local $TRUNK è diverged da origin/$TRUNK: $BEHIND behind, $GENUINE_AHEAD genuine ahead. Servono entrambe le riconciliazioni. Come procedo?"`
|
|
317
|
-
- Options: `[Rebase local $TRUNK su origin/$TRUNK]` / `[Mostrami i commit e fammi decidere]` / `[Abort]`.
|
|
318
|
-
|
|
319
|
-
5. **Log and proceed** — write to the tracker:
|
|
320
|
-
```
|
|
321
|
-
## Phase 0 — Workspace Hygiene Pre-flight
|
|
322
|
-
Status: PASS
|
|
323
|
-
Main repo: $MAIN
|
|
324
|
-
Trunk branch: $TRUNK
|
|
325
|
-
Dirty: <none | framework-telemetry-only (auto-ignored) | stashed: <message-label> | user-override>
|
|
326
|
-
Divergence (local…origin/$TRUNK): <0\t0 | framework-mgmt-only (auto-ignored: $FW_SKIPPED) | resolved: ff-pull | resolved: pushed | user-deferred>
|
|
327
|
-
Completed: <timestamp>
|
|
328
|
-
```
|
|
329
|
-
If any step ended in HALT, set `Status: HALT` and stop — do NOT continue to `## Pre-flight (once)`.
|
|
293
|
+
- Cards within the same `execution_strategy.groups` level (same `level`) run in parallel via isolated coder agents.
|
|
294
|
+
- Groups execute sequentially (group 0 → group 1 → group 2...).
|
|
295
|
+
- Review + QA run ONCE per group (combined), not per card.
|
|
296
|
+
- The orchestrator holds ONLY coordination state, never implementation details.
|
|
297
|
+
- File ownership map is enforced per-agent via MAY EDIT / FORBIDDEN lists.
|
|
298
|
+
- See "Team Mode" section below for full workflow.
|
|
299
|
+
|
|
300
|
+
### Common rules (both modes)
|
|
330
301
|
|
|
331
|
-
|
|
302
|
+
- The file-ownership map is the authoritative source for which files each agent may edit.
|
|
303
|
+
- When running parallel agents, expect "file modified since read" errors on shared files (like the backlog yml) — handle gracefully.
|
|
304
|
+
- When running in parallel, each parallel branch updates the tracker with its own card — use card ID as prefix to avoid conflicts.
|
|
332
305
|
|
|
333
306
|
---
|
|
334
307
|
|
|
335
|
-
## Pre-flight (once)
|
|
336
|
-
|
|
337
|
-
1. Read each backlog card from `${paths.backlog_dir}/*.yml` to understand scope and dependencies. Also read the project's canonical-docs registry — typically `${paths.references_dir}/ssot-registry.md` plus any linking-protocol guide — to understand which canonical docs exist for the feature area being implemented. Exact filenames are listed in `.baldart/overlays/new.md`; skip when absent.
|
|
338
|
-
1b. **Validate card fields (pre-flight gate)** — for each card, verify it has the minimum required fields before queuing it:
|
|
339
|
-
- `requirements` — must be a non-empty list (>=1 item)
|
|
340
|
-
- `acceptance_criteria` — must be a non-empty list (>=1 item)
|
|
341
|
-
- `files_likely_touched` — must be a non-empty list (>=1 file)
|
|
342
|
-
If any card fails: log the specific missing fields in `## Issues & Flags`, ask the user to fill them in before proceeding with that card, and continue pre-flight for any remaining valid cards.
|
|
343
|
-
|
|
344
|
-
1c. **Field Registry Validation (pre-flight gate)** — for each card with a `data_fields` block, run the project's field-validation tool if available (path listed in `.baldart/overlays/new.md`; typically `python3 tools/validate-card-fields.py <card-yaml-path>`).
|
|
345
|
-
- If exit 1: display the field errors in `## Issues & Flags` and HALT — ask the user to fix the card before proceeding. Do not start implementation until the card passes validation.
|
|
346
|
-
- If the card has DB-index signals (`db_indexes` — or legacy `firestore_indexes` — or `data.collections`/`data.tables`) but NO `data_fields` block: log WARNING in `## Issues & Flags` — "Card `<ID>` touches the persistence layer but has no `data_fields` block. Field/column names are unvalidated."
|
|
347
|
-
- Cards with no `data_fields` and no storage signals: skip silently.
|
|
348
|
-
- If the project does not ship a field-validation tool: skip this step.
|
|
349
|
-
2. Check `${paths.references_dir}/project-status.md` for current state (skip when absent).
|
|
350
|
-
3. Determine which cards can run in **parallel** (no shared files/components) vs which must be **sequential** (dependencies or overlapping paths). Use `group.sequence` to determine execution order within a group.
|
|
351
|
-
3b. **Build a file-ownership map** — for each card, enumerate every source file it is expected to touch (from `claimed_paths`, `paths`, and the implementation plan). Assign each file to **exactly one agent**. If two cards claim the same file, force those cards sequential on a single agent — do NOT spawn them in parallel. Record this map in the tracker under `## File Ownership Map`. This map is the authoritative source for all agent file permissions in Phase 2.
|
|
352
|
-
3c. **Complexity assessment — team mode decision**
|
|
353
|
-
|
|
354
|
-
Determine whether to use **team mode** (parallel coder agents with isolated contexts) or keep **sequential mode** (current behavior).
|
|
355
|
-
|
|
356
|
-
**Decision logic:**
|
|
357
|
-
|
|
358
|
-
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.
|
|
359
|
-
2. If no `execution_strategy` exists, compute:
|
|
360
|
-
- Count total cards in batch
|
|
361
|
-
- Count max cards in any single group (from `execution_strategy.groups[].cards`, i.e. cards sharing the same `level`)
|
|
362
|
-
- 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`.
|
|
363
|
-
3. Apply threshold:
|
|
364
|
-
- **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.
|
|
365
|
-
- **Team mode** if: total cards > 3 AND at least one group has 2+ cards.
|
|
366
|
-
4. Log decision in tracker:
|
|
367
|
-
```
|
|
368
|
-
## Execution Mode
|
|
369
|
-
Mode: team | sequential
|
|
370
|
-
Reason: [e.g., "6 cards, 3 parallel groups, max 3 cards in group 1"]
|
|
371
|
-
```
|
|
372
|
-
5. Inform the user:
|
|
373
|
-
```
|
|
374
|
-
Batch: N cards, M file unici
|
|
375
|
-
Gruppi paralleli: K livelli, max P card in parallelo
|
|
376
|
-
Modalita: **team mode** / **sequential mode** — [reason]
|
|
377
|
-
```
|
|
378
|
-
Proceed without asking (the PRD already approved the strategy).
|
|
379
|
-
|
|
380
|
-
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.
|
|
381
|
-
|
|
382
|
-
**→ Create the Task spine now.** The execution mode and (in team mode) the wave layout are resolved — create the native Task spine per § "Progress Visibility" A: `Pre-flight` (→ `in_progress`) + one task per card (wave-labelled in team mode) + `Final review` + `Merge & cleanup`. Emit the first Progress Bar with this batch's table. Mark `Pre-flight` → `completed` once worktree setup (step 5) finishes.
|
|
383
|
-
|
|
384
|
-
3d. **Codex batch cross-card grounding check** (runs in background during worktree setup)
|
|
385
|
-
|
|
386
|
-
> **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).
|
|
387
|
-
|
|
388
|
-
**Skip decision (provenance-aware — since v4.3.0).** The `/prd` Step 6.6 holistic audit (4-agent team + Codex adversarial pass) ALREADY ran this exact cross-card analysis over the cards when they were authored — its Codex prompt covers `files_likely_touched` conflicts, dependency shadows, implicit ordering, and shared-state mutation across the whole audited set. Re-running here is only worth the Codex call when **something changed between that audit and now**. Compute the skip before launching:
|
|
389
|
-
|
|
390
|
-
1. **Always skip** if the batch has only 1 card (no cross-card conflicts possible).
|
|
391
|
-
2. Otherwise, read `metadata.holistic_audit` from every card in the batch and evaluate the four SKIP conditions — **all must hold**:
|
|
392
|
-
- **S1 — provenance present**: every batch card has `metadata.holistic_audit` with non-empty `audited_at`, `audited_commit`, and `audited_set`. (Missing/partial on any card ⇒ condition fails.)
|
|
393
|
-
- **S2 — jointly audited**: all batch cards carry the **same** `audited_set` value (they were reviewed together, not stitched from separate PRD runs).
|
|
394
|
-
- **S3 — batch ⊆ audited set**: every batch card ID is present in that shared `audited_set`.
|
|
395
|
-
- **S4 — no drift on the claimed paths**: no commit touched any path the batch claims, between the audit baseline and the trunk this run grounds on. Using the shared `audited_commit` (`$AC`) and the batch's union of claimed/touched paths from the file-ownership map (step 3b, `$BATCH_PATHS`):
|
|
396
|
-
```bash
|
|
397
|
-
# empty AC, or AC not in history → treat as drift (do NOT skip)
|
|
398
|
-
DRIFT="$(git -C "$MAIN" log --oneline "$AC".."$TRUNK" -- $BATCH_PATHS 2>/dev/null || echo "DRIFT")"
|
|
399
|
-
```
|
|
400
|
-
S4 holds **iff** `$AC` is non-empty AND the command succeeds AND `$DRIFT` is empty.
|
|
401
|
-
3. **If S1–S4 all hold → SKIP the Codex cross-card check.** Log in the tracker under `## Cross-Card Conflicts (Codex)`:
|
|
402
|
-
`SKIPPED (provenance) — batch ⊆ holistic_audit set <audited_set>, no drift since <AC short sha> (audited <audited_at>)`. Then proceed to step 4 with the file-ownership map unchanged. Do NOT present anything to the user — this is a non-decision.
|
|
403
|
-
4. **Otherwise → RUN the check** (launch below). Record WHY in the same tracker section so the choice is auditable: `RUN — <reason>` where reason is one of `no/partial provenance` (S1) · `batch spans multiple audit sets` (S2) · `batch not a subset of audited set` (S3) · `drift on <first drifted path>` (S4).
|
|
404
|
-
|
|
405
|
-
`$MAIN` and `$TRUNK` are the same variables resolved in Phase 0. This gate degrades safely in every direction: any missing signal, ambiguity, or git error falls through to RUN — never to a silent skip.
|
|
406
|
-
|
|
407
|
-
Launch via `Bash` with `run_in_background: true` and `timeout: 300000`:
|
|
408
308
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
309
|
+
## Context recovery protocol
|
|
310
|
+
|
|
311
|
+
If at ANY point you are unsure where you are in the batch:
|
|
312
|
+
1. Read your tracker file (`/tmp/batch-tracker-<FIRST-CARD-ID>.md`)
|
|
313
|
+
2. Check `## Current Card` — if populated, resume that card at the listed phase.
|
|
314
|
+
3. **Re-Read the phase module** named in `## Current Card`'s `phase_module_loaded:` field (a compaction may have evacuated it from context — see § "Routing" HARD RULE). If the field is absent, map the listed phase to its module via the § "Routing" table and Read that.
|
|
315
|
+
4. Check `## Card Queue` — find the next unchecked card.
|
|
316
|
+
5. Check `## Completed Cards` — know what's already done (don't redo).
|
|
317
|
+
6. Continue the pipeline from where you left off.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
## Agent Routing (Phase 2 dispatcher)
|
|
323
|
+
|
|
324
|
+
Phase 2 reads the card's `owner_agent` field and dispatches to the matching
|
|
325
|
+
specialist. The enum's single source of truth is the **`owner_agent enum` block in
|
|
326
|
+
`framework/.claude/agents/REGISTRY.md`** (applied by `prd-card-writer.md § Agent
|
|
327
|
+
Specialization Rules`) and validated by the PRD validation phase
|
|
328
|
+
(`framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0).
|
|
329
|
+
|
|
330
|
+
| `owner_agent` | Dispatcher action in Phase 2 step 7 | Briefing variant |
|
|
331
|
+
|---|---|---|
|
|
332
|
+
| `coder` | Spawn `coder` | Standard coder briefing (default body below) |
|
|
333
|
+
| `ui-expert` | Spawn `ui-expert` | UI briefing — adds BLOCKING registry-first cascade + Post-Intervention Coherence Check (see step 7 § UI branch) |
|
|
334
|
+
| `plan` | Fallback to `coder` + WARN | Standard coder briefing + log `"[ROUTER] plan-only briefing not yet implemented — using coder"` |
|
|
335
|
+
| `visual-designer` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
|
|
336
|
+
| `motion-expert` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
|
|
337
|
+
| 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"` |
|
|
338
|
+
| 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) |
|
|
339
|
+
|
|
340
|
+
The three `plan` / `visual-designer` / `motion-expert` stubs exist so the
|
|
341
|
+
router never blocks a card; specialized briefings are tracked as a follow-up.
|
|
342
|
+
**Only the empty/missing/`claude` legacy placeholders fall back to `coder`** — a
|
|
343
|
+
genuinely unrecognized value (e.g. a typo `coder-agent`, or an agent not in the
|
|
344
|
+
enum) HALTs so a mis-routed card is never silently downgraded. The table and the
|
|
345
|
+
step-6b pseudocode are the same contract stated twice; keep them in lockstep.
|
|
346
|
+
|
|
347
|
+
The valid values come from ONE place — `REGISTRY.md`'s `owner_agent enum` block. Do not
|
|
348
|
+
re-list them here or maintain parallel copies; if the roster changes, edit the enum in
|
|
349
|
+
`REGISTRY.md` and these consumers read it:
|
|
350
|
+
|
|
351
|
+
- `framework/.claude/skills/prd/assets/card-template.yml` (the placeholder cites the REGISTRY enum),
|
|
352
|
+
- `framework/.claude/agents/prd-card-writer.md § Agent Specialization Rules`,
|
|
353
|
+
- `framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0a,
|
|
354
|
+
- `framework/.claude/agents/REGISTRY.md` decision-tree.
|
|
443
355
|
|
|
444
|
-
|
|
445
|
-
- `${CARD_PATHS}`: newline-separated list of all `- ${paths.backlog_dir}/FEAT-XXXX-*.yml` paths in the batch
|
|
446
|
-
- `${FILE_OWNERSHIP_MAP}`: the file-ownership map built in step 3b
|
|
447
|
-
|
|
448
|
-
> `<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.
|
|
449
|
-
|
|
450
|
-
**Result handling** (read before Phase 1 of first card):
|
|
451
|
-
- **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.
|
|
452
|
-
- **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.
|
|
453
|
-
- Read the exact `$AUDIT_FILE` path recorded in the tracker after the background command completes.
|
|
454
|
-
- 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.
|
|
455
|
-
- If **PASS** or file empty: proceed normally.
|
|
456
|
-
- If **conflicts found**: log in tracker under `## Cross-Card Conflicts (Codex)` and present to user. For each conflict:
|
|
457
|
-
- `FILE_CONFLICT` / `ORDER_RISK` → force the conflicting cards sequential (update file-ownership map).
|
|
458
|
-
- `IMPLICIT_DEP` → add `depends_on` entry to tracker notes (do NOT modify backlog YAML).
|
|
459
|
-
- `STATE_MUTATION` → add warning to both cards' Phase 2 briefings.
|
|
460
|
-
|
|
461
|
-
4. **Worktree setup** — delegate to the **worktree-manager** skill (`/nw` in programmatic mode):
|
|
462
|
-
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.
|
|
463
|
-
b. Pass all card IDs, their `group.parent` fields, AND the resolved `slug` to the skill's grouping logic.
|
|
464
|
-
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.
|
|
465
|
-
d. The skill updates `.worktrees/registry.json` with the worktree entry (including all card IDs in the `cards` field).
|
|
466
|
-
e. If build fails → the skill STOPs and reports. Do NOT continue.
|
|
467
|
-
f. Record the worktree path, branch, slug, and port from the skill's output in the tracker.
|
|
468
|
-
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).
|
|
469
|
-
6. Create a task list to track progress across all cards.
|
|
356
|
+
Keep them in lockstep — drift between any two layers silently mis-routes cards.
|
|
470
357
|
|
|
471
358
|
---
|
|
472
359
|
|
|
360
|
+
|
|
473
361
|
## QA Profile Selector
|
|
474
362
|
|
|
475
363
|
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.**
|
|
@@ -495,6 +383,7 @@ disagree.
|
|
|
495
383
|
|
|
496
384
|
---
|
|
497
385
|
|
|
386
|
+
|
|
498
387
|
## Trivial-card fast-lane (since v4.6.0 — SSOT; phases below CITE this, never redefine it)
|
|
499
388
|
|
|
500
389
|
Some cards are genuinely too small to justify the review machine: a `docs`/`chore`/`config`
|
|
@@ -552,678 +441,65 @@ diff + 0 triggers` — a deterministic, card-authored gate reason. Never `time b
|
|
|
552
441
|
|
|
553
442
|
---
|
|
554
443
|
|
|
555
|
-
## Agent Routing (Phase 2 dispatcher)
|
|
556
|
-
|
|
557
|
-
Phase 2 reads the card's `owner_agent` field and dispatches to the matching
|
|
558
|
-
specialist. The enum's single source of truth is the **`owner_agent enum` block in
|
|
559
|
-
`framework/.claude/agents/REGISTRY.md`** (applied by `prd-card-writer.md § Agent
|
|
560
|
-
Specialization Rules`) and validated by the PRD validation phase
|
|
561
|
-
(`framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0).
|
|
562
|
-
|
|
563
|
-
| `owner_agent` | Dispatcher action in Phase 2 step 7 | Briefing variant |
|
|
564
|
-
|---|---|---|
|
|
565
|
-
| `coder` | Spawn `coder` | Standard coder briefing (default body below) |
|
|
566
|
-
| `ui-expert` | Spawn `ui-expert` | UI briefing — adds BLOCKING registry-first cascade + Post-Intervention Coherence Check (see step 7 § UI branch) |
|
|
567
|
-
| `plan` | Fallback to `coder` + WARN | Standard coder briefing + log `"[ROUTER] plan-only briefing not yet implemented — using coder"` |
|
|
568
|
-
| `visual-designer` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
|
|
569
|
-
| `motion-expert` | Fallback to `coder` + WARN | Standard coder briefing + same WARN format |
|
|
570
|
-
| 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"` |
|
|
571
|
-
| 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) |
|
|
572
|
-
|
|
573
|
-
The three `plan` / `visual-designer` / `motion-expert` stubs exist so the
|
|
574
|
-
router never blocks a card; specialized briefings are tracked as a follow-up.
|
|
575
|
-
**Only the empty/missing/`claude` legacy placeholders fall back to `coder`** — a
|
|
576
|
-
genuinely unrecognized value (e.g. a typo `coder-agent`, or an agent not in the
|
|
577
|
-
enum) HALTs so a mis-routed card is never silently downgraded. The table and the
|
|
578
|
-
step-6b pseudocode are the same contract stated twice; keep them in lockstep.
|
|
579
|
-
|
|
580
|
-
The valid values come from ONE place — `REGISTRY.md`'s `owner_agent enum` block. Do not
|
|
581
|
-
re-list them here or maintain parallel copies; if the roster changes, edit the enum in
|
|
582
|
-
`REGISTRY.md` and these consumers read it:
|
|
583
|
-
|
|
584
|
-
- `framework/.claude/skills/prd/assets/card-template.yml` (the placeholder cites the REGISTRY enum),
|
|
585
|
-
- `framework/.claude/agents/prd-card-writer.md § Agent Specialization Rules`,
|
|
586
|
-
- `framework/.claude/skills/prd/references/validation-phase.md` Step 6 → 0a,
|
|
587
|
-
- `framework/.claude/agents/REGISTRY.md` decision-tree.
|
|
588
|
-
|
|
589
|
-
Keep them in lockstep — drift between any two layers silently mis-routes cards.
|
|
590
|
-
|
|
591
|
-
---
|
|
592
|
-
|
|
593
|
-
## Per-card pipeline
|
|
594
|
-
|
|
595
|
-
For each card, execute these phases in order:
|
|
596
|
-
|
|
597
|
-
### Phase 1 — Claim & Context
|
|
598
|
-
1. **Update tracker**: set current card, phase = "1-claim".
|
|
599
|
-
2. **`depends_on` gate (BEFORE claiming)** — read the card's `depends_on` field. For each listed card ID:
|
|
600
|
-
- Read that card's backlog YAML and check its `status` field.
|
|
601
|
-
- 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).
|
|
602
|
-
- If `DONE` (or the user chose "proceed anyway") → continue.
|
|
603
|
-
2b. **Claim** — only now set the card status to `IN_PROGRESS` and assign yourself. **→ Visibility**: TaskUpdate this card's spine task → `in_progress`, and emit a Progress Bar (card change) per § "Progress Visibility".
|
|
604
|
-
2c. **Trivial-card classification (BLOCKING gate for steps 3–4)** — evaluate `IS_TRIVIAL(card)` per § "Trivial-card fast-lane". Note: condition 3 (non-source diff) cannot be fully evaluated until the coder has produced the diff, so at this point compute the **provisional** trivial flag from conditions 1+2 only (`review_profile == skip` AND no Step-A trigger sourced from the card YAML text + `files_likely_touched` extensions — if EVERY path in `files_likely_touched` is non-source, condition 3 is provisionally satisfied). If provisionally trivial → **SKIP steps 3, 3a, and 4** (architecture grounding); log `trivial: architecture grounding skipped (review_profile=skip + non-source files_likely_touched + 0 triggers)` and jump to Phase 2. Re-confirm `IS_TRIVIAL` on the ACTUAL committed diff at the review gates (Phase 2.55/3.5/3.7); if the coder unexpectedly touched a source file, the guard flips the card back onto the normal review path there. If NOT provisionally trivial → run steps 3, 3a, 4 as normal.
|
|
605
|
-
3. **(skip when provisionally trivial — see 2c)** Invoke the **codebase-architect** agent (MUST per AGENTS.md) to understand the relevant codebase area, existing patterns, and architecture before any implementation. When `features.has_lsp_layer: true`, the architect uses LSP find-references for identifier-shaped lookups — this needs NO handoff from the orchestrator: the architect reads `features.has_lsp_layer` from `baldart.config.yml` directly (the flag is ambient) per `agents/code-search-protocol.md`. The orchestrator does NOT propagate the flag. (Earlier doc versions numbered this step 4; the step that read project-status BEFORE the architect was removed because it persisted pre-analysis context — see step 3a.)
|
|
606
|
-
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.
|
|
607
|
-
4. **Plan-auditor grounding check** — but first, a **provenance skip (since v4.7.0 — mirror of Step 3d)**: the `/prd` Step 6.6 holistic audit already ran a per-card grounding pass when the card was authored. Re-grounding here is only worth a plan-auditor spawn if something changed since. Skip the plan-auditor when **BOTH** hold:
|
|
608
|
-
- **P1 — provenance present**: the card has `metadata.holistic_audit` with non-empty `audited_at`, `audited_commit`, `audited_set`.
|
|
609
|
-
- **P2 — no drift on this card's claimed paths** since the audit baseline. With `$AC` = `metadata.holistic_audit.audited_commit`, `$MAIN`/`$TRUNK` from the tracker, and this card's `files_likely_touched`/claimed paths (`$CARD_PATHS`):
|
|
610
|
-
```bash
|
|
611
|
-
# empty AC, AC not in history, or any git error → treat as drift (do NOT skip)
|
|
612
|
-
DRIFT="$(git -C "$MAIN" log --oneline "$AC".."$TRUNK" -- $CARD_PATHS 2>/dev/null || echo "DRIFT")"
|
|
613
|
-
```
|
|
614
|
-
P2 holds **iff** `$AC` is non-empty AND the command succeeds AND `$DRIFT` is empty.
|
|
615
|
-
|
|
616
|
-
(No S2/S3 cross-card conditions — grounding is per-card, and the holistic audit grounded each card individually.) If **P1 ∧ P2 → SKIP** the plan-auditor: log `plan-auditor grounding: SKIPPED (holistic_audit provenance, no drift on claimed paths since <AC short sha>)`, carry the card requirements unchanged into Phase 2, and proceed to step 5. **Fail-safe**: missing/partial provenance, any drift, or any git error → fall through to RUN the plan-auditor as written below (never a silent skip). Independent of the trivial fast-lane (a trivial card already skipped steps 3–4 at step 2c). Otherwise — invoke the **plan-auditor** agent in **QUICK mode** (pass `mode: QUICK`; its contract runs only the grounding checks, and because the codebase-architect findings are passed in below it does NOT re-spawn codebase-architect for this narrow check):
|
|
617
|
-
```
|
|
618
|
-
mode: QUICK
|
|
619
|
-
Grounding check only (NOT a full audit — do not run the full AUDIT CHECKLIST A-H, and do not
|
|
620
|
-
re-invoke codebase-architect; the findings are pasted below). Verify this backlog card's
|
|
621
|
-
requirements are grounded in the actual codebase.
|
|
622
|
-
|
|
623
|
-
Check:
|
|
624
|
-
1. Do all paths in files_likely_touched actually exist?
|
|
625
|
-
2. Are all type/field references in requirements correct per the codebase findings below?
|
|
626
|
-
3. Are any [ASSUMED] items answerable by reading the listed files (i.e., should be verified facts)?
|
|
627
|
-
4. Do any requirements conflict with known anti-patterns from your memory?
|
|
628
|
-
|
|
629
|
-
Card YAML:
|
|
630
|
-
[paste full card YAML]
|
|
631
|
-
|
|
632
|
-
Codebase-architect findings:
|
|
633
|
-
[paste key findings from step 3]
|
|
634
|
-
|
|
635
|
-
Return: PASS | FIXES NEEDED (list exact corrections). No full audit report needed.
|
|
636
|
-
```
|
|
637
|
-
- 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.
|
|
638
|
-
- If **PASS**: proceed.
|
|
639
|
-
5. **Update tracker**: phase = "1-claim DONE", log codebase-architect key findings (1-2 lines) and plan-auditor result (PASS or corrections applied).
|
|
640
|
-
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.
|
|
641
|
-
|
|
642
|
-
### Phase 2 — Implement (self-healing, up to 3 retries)
|
|
643
|
-
6. **Update tracker**: phase = "2-implement".
|
|
644
|
-
6b. **Agent dispatch (router)** — read `owner_agent` from the card YAML and resolve the spawn target per the table in § Agent Routing above:
|
|
645
|
-
|
|
646
|
-
```
|
|
647
|
-
Let raw = card.owner_agent (string, may be missing).
|
|
648
|
-
# Epic guard FIRST — an epic is a tracker, not implementable work.
|
|
649
|
-
If card is an epic (id ends "-00" OR filename ends "-epic.yml" OR review_profile == "skip"
|
|
650
|
-
with no requirements): SKIP — do NOT dispatch to any agent. Log
|
|
651
|
-
"[ROUTER] card <ID> is an epic (tracker) — skipped, not implemented" and move to the next card.
|
|
652
|
-
Switch on raw:
|
|
653
|
-
- "coder" → spawn = "coder", briefing = "coder"
|
|
654
|
-
- "ui-expert" → spawn = "ui-expert", briefing = "ui-expert"
|
|
655
|
-
- "plan" → spawn = "coder", briefing = "coder"
|
|
656
|
-
+ log: "[ROUTER] plan-only briefing not yet implemented — using coder"
|
|
657
|
-
- "visual-designer" → spawn = "coder", briefing = "coder"
|
|
658
|
-
+ log: "[ROUTER] visual-designer briefing not yet implemented — using coder"
|
|
659
|
-
- "motion-expert" → spawn = "coder", briefing = "coder"
|
|
660
|
-
+ log: "[ROUTER] motion-expert briefing not yet implemented — using coder"
|
|
661
|
-
- "" | missing | "claude"
|
|
662
|
-
→ spawn = "coder", briefing = "coder"
|
|
663
|
-
+ log: "[ROUTER] card <ID> has no valid owner_agent (got '<raw>'); defaulting to coder"
|
|
664
|
-
- anything else → HALT. Log: "[ROUTER] card <ID> has unknown owner_agent '<raw>' — not in {coder, ui-expert, plan, visual-designer, motion-expert}. Ask the user how to proceed."
|
|
665
|
-
```
|
|
666
|
-
|
|
667
|
-
Log the resolved `spawn` and `briefing` in the tracker (1 line: `"router: owner_agent=<raw> → spawn=<agent>, briefing=<variant>"`). This is the audit trail for which specialist actually handled the card.
|
|
668
|
-
|
|
669
|
-
7. Spawn the **resolved agent** (from step 6b) using this **standardized mission briefing** — fill in each section from the card YAML, tracker, and codebase-architect findings. When `briefing = "ui-expert"`, ALSO include the additional UI sections marked **[UI-ONLY]** below:
|
|
670
|
-
|
|
671
|
-
```
|
|
672
|
-
## MISSION BRIEFING — <CARD-ID>
|
|
673
|
-
|
|
674
|
-
### Card Specification (verbatim — do not paraphrase)
|
|
675
|
-
Requirements:
|
|
676
|
-
[copy full requirements list from card YAML, including any corrections from the plan-auditor grounding check (step 4)]
|
|
677
|
-
|
|
678
|
-
Acceptance Criteria:
|
|
679
|
-
[copy full acceptance_criteria list from card YAML]
|
|
680
|
-
|
|
681
|
-
### Unknowns & Conditional Requirements (MANDATORY — resolve before coding)
|
|
682
|
-
[If card has `unknowns` field: copy verbatim. If empty or absent: "None."]
|
|
683
|
-
|
|
684
|
-
Each unknown that says "verify X; if missing → do Y" is a BINARY-OUTCOME ITEM.
|
|
685
|
-
You MUST actively verify and produce one of the two outcomes (implementation OR TODO comment).
|
|
686
|
-
See `coder.md § Conditional Requirements — Binary-Outcome Items`.
|
|
687
|
-
|
|
688
|
-
### Business Context (WHY this feature exists)
|
|
689
|
-
[paste business_rationale field from card YAML]
|
|
690
|
-
[if field is empty/missing, read PRD Section 1b from card's links.prd path]
|
|
691
|
-
|
|
692
|
-
### Codebase Context
|
|
693
|
-
[paste codebase-architect key findings: file paths, exact line numbers, type signatures, existing patterns to follow]
|
|
694
|
-
[include any corrections or anti-patterns flagged by plan-auditor grounding check]
|
|
695
|
-
|
|
696
|
-
### Design Reference (UI cards only — include if card has links.design)
|
|
697
|
-
Design file: [path from card's links.design field]
|
|
698
|
-
Read the design.html file and use it as the visual reference for your implementation.
|
|
699
|
-
The design was approved by the user — your implementation MUST match it.
|
|
700
|
-
|
|
701
|
-
### [UI-ONLY] Registry-first BLOCKING pre-work (include ONLY when briefing = "ui-expert")
|
|
702
|
-
You are spawned as `ui-expert`. Before writing any UI code, you MUST complete
|
|
703
|
-
the registry-first cascade defined in
|
|
704
|
-
`framework/.claude/agents/ui-expert.md` § "Authoritative Style Reference —
|
|
705
|
-
Registry-First Protocol" (the SSOT lives in
|
|
706
|
-
`framework/agents/design-system-protocol.md`). Reproduce its 5 steps
|
|
707
|
-
verbatim, do NOT paraphrase or skip:
|
|
708
|
-
|
|
709
|
-
1. Read `${paths.design_system}/INDEX.md` (component index + Canonical
|
|
710
|
-
Authority Matrix).
|
|
711
|
-
2. Read `${paths.ui_guidelines}` (visual language, typography,
|
|
712
|
-
accessibility, brand voice).
|
|
713
|
-
3. Read `${paths.design_system}/tokens-reference.md` (token contract —
|
|
714
|
-
SSOT for every color / spacing / shadow / radius / motion value).
|
|
715
|
-
4. For EACH primitive in scope on this card, read
|
|
716
|
-
`${paths.design_system}/components/<Name>.md`. "In scope" = any
|
|
717
|
-
component named in the mockup, the requirements, or `files_likely_touched`.
|
|
718
|
-
5. For EACH pattern in scope, read the relevant
|
|
719
|
-
`${paths.design_system}/patterns/<topic>.md`.
|
|
720
|
-
|
|
721
|
-
State, in your first response, which Authority Matrix rows govern this
|
|
722
|
-
card, which component specs you read (step 4), and which patterns you
|
|
723
|
-
read (step 5). Skipping this declaration = the orchestrator will reject
|
|
724
|
-
the implementation and re-spawn.
|
|
725
|
-
|
|
726
|
-
The `features.has_design_system: true` flag in `baldart.config.yml` is
|
|
727
|
-
the precondition for the full cascade. When `features.has_design_system:
|
|
728
|
-
false`, only step 2 applies — log the gap, recommend `/design-system-init`
|
|
729
|
-
if drift is visible, and proceed with coder-level diligence (no cascade
|
|
730
|
-
enforced).
|
|
731
|
-
|
|
732
|
-
### [UI-ONLY] Implementation-only constraint (include ONLY when briefing = "ui-expert")
|
|
733
|
-
This `/new` invocation gives you the role of IMPLEMENTER, not designer:
|
|
734
|
-
|
|
735
|
-
- DO NOT redesign the mockup. The mockup at `links.design` is the
|
|
736
|
-
user-approved visual contract for this card.
|
|
737
|
-
- DO NOT silently adapt a mockup detail that conflicts with the registry
|
|
738
|
-
(e.g. a custom shadow not in `tokens-reference.md`, a font size off the
|
|
739
|
-
type scale, a color outside the palette). If you find such a conflict:
|
|
740
|
-
STOP, log it in the tracker as `[DS-DRIFT] mockup-vs-registry`, and ask
|
|
741
|
-
the user which side to honor.
|
|
742
|
-
- DO NOT extend scope into business logic, API calls, state management, or
|
|
743
|
-
validation rules. Those belong to a sibling `coder` card (see
|
|
744
|
-
`backlog-phase.md § Rule B`). If a requirement appears to need logic,
|
|
745
|
-
STOP and ask — do not implement it.
|
|
746
|
-
|
|
747
|
-
### [UI-ONLY] Post-Intervention Coherence Check (include ONLY when briefing = "ui-expert")
|
|
748
|
-
Before declaring the card done, you MUST reconcile the three design-system
|
|
749
|
-
sources in the SAME commit as your UI change, per
|
|
750
|
-
`framework/agents/design-system-protocol.md § Post-Intervention Coherence Check`:
|
|
751
|
-
|
|
752
|
-
- `${paths.design_system}/INDEX.md` — add / update entries for any primitive
|
|
753
|
-
introduced or modified. Drift code: `DS_INDEX_DRIFT`.
|
|
754
|
-
- `${paths.design_system}/components/<Name>.md` — ship the per-component
|
|
755
|
-
spec for any new primitive; update the spec when a primitive's API or
|
|
756
|
-
visual changes. Drift code: `DS_COMPONENT_STALE`.
|
|
757
|
-
- `${paths.design_system}/tokens-reference.md` — add / update token entries
|
|
758
|
-
when introducing new semantic tokens. Drift code: `DS_TOKENS_DRIFT`.
|
|
759
|
-
|
|
760
|
-
The four conditions defined in `design-system-protocol.md` are the SSOT —
|
|
761
|
-
reproduce them in your completion report under a `design_system_coherence:`
|
|
762
|
-
block listing which conditions applied and which artifacts you updated.
|
|
763
|
-
Omitting the block = the orchestrator treats the card as not done.
|
|
764
|
-
|
|
765
|
-
### File Permissions (ENFORCED — no exceptions)
|
|
766
|
-
MAY EDIT — your files for this card:
|
|
767
|
-
[list from ownership map for this card]
|
|
768
|
-
|
|
769
|
-
MUST READ ONLY — shared dependencies:
|
|
770
|
-
[list from ownership map: files owned by other cards that this card reads]
|
|
771
|
-
|
|
772
|
-
FORBIDDEN:
|
|
773
|
-
- Do NOT edit any file outside the MAY EDIT list above
|
|
774
|
-
- Do NOT refactor unrelated code
|
|
775
|
-
- Do NOT add unrequested features or extra error handling beyond what's specified
|
|
776
|
-
- Do NOT modify test files unless the card explicitly requires it
|
|
777
|
-
|
|
778
|
-
### Database Indexes (if card has `db_indexes` — or legacy `firestore_indexes` — field)
|
|
779
|
-
This card requires the following indexes shipped in the SAME commit as the query
|
|
780
|
-
code. Missing indexes degrade performance or break production (variant per
|
|
781
|
-
`stack.database` — see `framework/.claude/agents/coder.md § Database Index Invariant`).
|
|
782
|
-
|
|
783
|
-
[paste db_indexes entries from card YAML, formatted as:]
|
|
784
|
-
| Entity | Dialect | Fields | Kind | Query Location | PRD Ref |
|
|
785
|
-
|--------|---------|--------|------|----------------|---------|
|
|
786
|
-
| [entity] | [stack.database] | [field1 ASC, field2 DESC] | [composite/covering/GIN/GSI] | [file path] | [IDX-N] |
|
|
787
|
-
|
|
788
|
-
**Where to ship the index — pick the artifact matching `stack.database`:**
|
|
789
|
-
|
|
790
|
-
- `firestore` → append to `firestore.indexes.json` under `indexes[]`:
|
|
791
|
-
```json
|
|
792
|
-
{
|
|
793
|
-
"collectionGroup": "<entity>",
|
|
794
|
-
"queryScope": "COLLECTION",
|
|
795
|
-
"fields": [
|
|
796
|
-
{ "fieldPath": "<field1>", "order": "ASCENDING" },
|
|
797
|
-
{ "fieldPath": "<field2>", "order": "DESCENDING" }
|
|
798
|
-
]
|
|
799
|
-
}
|
|
800
|
-
```
|
|
801
|
-
Stage `firestore.indexes.json` together with the query code.
|
|
802
|
-
- `postgres` / `supabase` / `mysql` / `sqlite` → add a migration file under the
|
|
803
|
-
project's migrations dir (`migrations/`, `db/migrate/`, `supabase/migrations/`,
|
|
804
|
-
`prisma/migrations/` per project convention) with `CREATE INDEX ...` or the
|
|
805
|
-
Prisma `@@index([...])` directive. For Supabase, RLS policies live in the same
|
|
806
|
-
migration when relevant.
|
|
807
|
-
- `mongodb` → add `db.<entity>.createIndex(...)` to the project's index-bootstrap
|
|
808
|
-
script (path declared in `.baldart/overlays/new.md § Schema Bootstrap`), or run
|
|
809
|
-
it as part of the migration command.
|
|
810
|
-
- `dynamodb` → update the table definition in the project's IaC (CDK / Terraform /
|
|
811
|
-
SAM / SST) with the matching GSI/LSI.
|
|
812
|
-
- Stack `none` or unset → if you still see `db_indexes` on the card, ask the user
|
|
813
|
-
to confirm the persistence target before staging anything.
|
|
814
|
-
|
|
815
|
-
Stage the index artifact alongside the query code in the SAME commit. Verification
|
|
816
|
-
(post-deploy index propagation) is handled in the Production Readiness Checklist
|
|
817
|
-
section below, branched by `stack.deployment`.
|
|
818
|
-
|
|
819
|
-
### Expected Output Locations
|
|
820
|
-
[pre-fill from codebase-architect: for each requirement, the file:line where the change should go]
|
|
821
|
-
|
|
822
|
-
### Project Anti-Patterns & NFRs (ENFORCED)
|
|
823
|
-
Violating these is a BLOCKER in code review.
|
|
824
|
-
|
|
825
|
-
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):
|
|
826
|
-
[resolved list of this project's deprecated/anti-patterns, or "None documented."]
|
|
827
|
-
|
|
828
|
-
Performance MUST rules (adapt to your stack):
|
|
829
|
-
- Bounded reads on every database query (`.limit()` / equivalent)
|
|
830
|
-
- Cursor-based pagination, not offset
|
|
831
|
-
- No per-row fetches in loops — batch instead
|
|
832
|
-
- Database indexes declared in schema config (same commit as the query that needs them)
|
|
833
|
-
|
|
834
|
-
Security MUST rules:
|
|
835
|
-
- No stack traces in HTTP responses — generic messages + error codes only
|
|
836
|
-
- No PII in console.log or error tracking
|
|
837
|
-
- No hardcoded secrets — env vars only
|
|
838
|
-
- ALL non-public routes MUST use the project's auth middleware
|
|
839
|
-
|
|
840
|
-
Coding standards (agents/coding-standards.md):
|
|
841
|
-
- Use the project's canonical terminology (document it in coding-standards.md)
|
|
842
|
-
- Honor the design-system theming contract (e.g. text/background pairing rules)
|
|
843
|
-
- Honor the project's image-format and asset-pipeline rules
|
|
844
|
-
|
|
845
|
-
Design System SSOT (MANDATORY for UI cards):
|
|
846
|
-
- Master reference: `${paths.design_system}/INDEX.md` (component index + Canonical Authority
|
|
847
|
-
Matrix + Quick rules MUST). Read this BEFORE touching any UI file.
|
|
848
|
-
- For each UI component you modify or create, read `${paths.design_system}/components/<Name>.md`.
|
|
849
|
-
- Merchant-themed surfaces MUST follow the pairing rule in
|
|
850
|
-
`the project's theming pattern doc (listed in `.baldart/overlays/ui-design.md`)`.
|
|
851
|
-
- Motion MUST follow `the project's motion pattern doc (listed in `.baldart/overlays/ui-design.md`)` (reduced-motion variants
|
|
852
|
-
required). The coder agent's own hardening (see `.claude/agents/coder.md`) already enforces
|
|
853
|
-
this — this briefing is an explicit reminder for UI-touching cards.
|
|
854
|
-
- No hardcoded hex/shadow/border values in component styling — canonical tokens only.
|
|
855
|
-
|
|
856
|
-
### Batch Lessons (from prior cards in this batch)
|
|
857
|
-
[If tracker `## Lessons Learned` has entries, paste them here.
|
|
858
|
-
If empty or first card: "First card — no lessons yet."]
|
|
859
|
-
|
|
860
|
-
### MANDATORY: Numbered Requirements Checklist (anti-skip measure)
|
|
861
|
-
Before you start coding, print this checklist to confirm you see ALL requirements:
|
|
862
|
-
```
|
|
863
|
-
REQUIREMENTS TO IMPLEMENT:
|
|
864
|
-
[x] R1: [requirement text]
|
|
865
|
-
[x] R2: [requirement text]
|
|
866
|
-
...
|
|
867
|
-
ACCEPTANCE CRITERIA TO SATISFY:
|
|
868
|
-
[x] AC1: [criterion text]
|
|
869
|
-
[x] AC2: [criterion text]
|
|
870
|
-
...
|
|
871
|
-
CONDITIONAL / BINARY-OUTCOME ITEMS (from unknowns + requirements with "verify if / if missing"):
|
|
872
|
-
[ ] C1: [item text] → Branch to take: A (found+implement) | B (missing+TODO)
|
|
873
|
-
[ ] C2: [item text] → Branch to take: A (found+implement) | B (missing+TODO)
|
|
874
|
-
...
|
|
875
|
-
Total: N requirements + M acceptance criteria + K conditional items = X items
|
|
876
|
-
```
|
|
877
|
-
You MUST implement ALL items. Skipping even one is a failure.
|
|
878
|
-
For each conditional item: verify actively, then produce the correct branch artifact.
|
|
879
|
-
|
|
880
|
-
### MANDATORY: Completion Report
|
|
881
|
-
When implementation is done, output this block in EXACTLY this format.
|
|
882
|
-
This report is NOT optional — if you omit it, the orchestrator will flag
|
|
883
|
-
your implementation as incomplete and spawn a fix agent.
|
|
884
|
-
|
|
885
|
-
```completion-report
|
|
886
|
-
card: <CARD-ID>
|
|
887
|
-
requirements:
|
|
888
|
-
- id: 1
|
|
889
|
-
text: "[verbatim requirement text]"
|
|
890
|
-
status: done | not_implemented
|
|
891
|
-
evidence: "src/path/to/file.ts:LINE_NUMBER"
|
|
892
|
-
notes: "[if not_implemented: explain why]"
|
|
893
|
-
- id: 2
|
|
894
|
-
[repeat for each requirement]
|
|
895
|
-
acceptance_criteria:
|
|
896
|
-
- id: 1
|
|
897
|
-
text: "[verbatim criterion text]"
|
|
898
|
-
status: done | not_implemented
|
|
899
|
-
evidence: "src/path/to/file.ts:LINE_NUMBER"
|
|
900
|
-
items_total: [N]
|
|
901
|
-
items_done: [M]
|
|
902
|
-
items_skipped: [list of skipped item IDs, or "none"]
|
|
903
|
-
conditional_items:
|
|
904
|
-
- item: "[verbatim text of conditional requirement]"
|
|
905
|
-
branch_taken: "A-found" | "B-missing"
|
|
906
|
-
evidence: "src/path/to/file.ts:LINE_NUMBER"
|
|
907
|
-
notes: "[if B-missing: exact TODO location and text left; otherwise omit]"
|
|
908
|
-
```
|
|
909
|
-
|
|
910
|
-
Per-requirement / per-AC `status` is BINARY: `done` or `not_implemented` (the legacy
|
|
911
|
-
`partial`/`blocked` values are removed — see `coder.md`). The orchestrator re-derives the
|
|
912
|
-
finer Done/Partial/Missing classification itself in Phase 2.5 by reading the code; the coder
|
|
913
|
-
report is a starting signal, not ground truth.
|
|
914
|
-
If `items_skipped` is not "none", you MUST explain why each was skipped.
|
|
915
|
-
The orchestrator treats any `not_implemented` or skipped item as a gap requiring a fix agent.
|
|
916
|
-
`conditional_items` MUST list every binary-outcome item from the card. If the card has no
|
|
917
|
-
conditional requirements, omit the field. `branch_taken: B-missing` MUST have a `notes`
|
|
918
|
-
field with the exact file path and line where the TODO comment was written.
|
|
919
|
-
```
|
|
920
|
-
|
|
921
|
-
8. **Run the verification gates and CAPTURE their output to disk** (so step 9 can pass it to a fix agent) — **redirect, never `tee`/stream inline** (per § "Context economy" → Gate-output discipline). Each is its own gate:
|
|
922
|
-
```bash
|
|
923
|
-
cd <worktree-path>
|
|
924
|
-
npm run lint > /tmp/lint-<CARD-ID>.txt 2>&1; echo "lint:$?"
|
|
925
|
-
# tsc is its OWN blocking gate — run it ONLY when stack.language includes "typescript"
|
|
926
|
-
# (do NOT assume `npm run build` covers tsc — Next.js dev builds and many setups skip it):
|
|
927
|
-
npx tsc --noEmit > /tmp/tsc-<CARD-ID>.txt 2>&1; echo "tsc:$?" # guard: when stack.language includes "typescript"
|
|
928
|
-
npm test > /tmp/test-<CARD-ID>.txt 2>&1; echo "test:$?" # if tests exist
|
|
929
|
-
npm run build > /tmp/build-<CARD-ID>.txt 2>&1; echo "build:$?"
|
|
930
|
-
```
|
|
931
|
-
The `echo "<gate>:$?"` lines surface only the **exit code** inline — the full log stays on disk. 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. On a non-zero exit, read a **bounded** extract only (`tail -n 30 /tmp/<gate>-<CARD-ID>.txt`), never the whole log — do NOT run the gates without redirect-to-file capture.
|
|
932
|
-
9. **If any check fails**: categorize the error (`lint | TypeScript | test | build`), log it in the tracker as `retry-cause: <category>`.
|
|
933
|
-
**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.
|
|
934
|
-
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 **path** to the captured gate log (`/tmp/<gate>-<CARD-ID>.txt` — it Reads the log itself; do NOT inline-paste the full log into its prompt), the error category, and the explicit list of files it may edit. 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.
|
|
935
|
-
10. If still failing after 3 retries (or on a stuck loop), log the failure in `## Issues & Flags` and ask the user before continuing.
|
|
936
|
-
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).
|
|
937
|
-
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:
|
|
938
|
-
```bash
|
|
939
|
-
cd <worktree-path>
|
|
940
|
-
git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD
|
|
941
|
-
```
|
|
942
|
-
(`$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.)
|
|
943
|
-
Compare against this card's allowed files in `## File Ownership Map`.
|
|
944
|
-
- **All within allowed set** → proceed to Phase 2.5.
|
|
945
|
-
- **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.
|
|
946
|
-
|
|
947
|
-
### Phase 2.5 — Implementation Completeness Check (MANDATORY)
|
|
948
|
-
|
|
949
|
-
Before triggering any review, you MUST verify that the coder agent implemented **every requirement and acceptance criterion** in the backlog card. This is a blocking gate — do NOT proceed to Phase 3 with unimplemented items.
|
|
950
|
-
|
|
951
|
-
**Step-by-step**:
|
|
952
|
-
|
|
953
|
-
0. **Conditional requirements pre-scan** (BLOCKING — before building the main checklist):
|
|
954
|
-
|
|
955
|
-
Scan the card's `requirements`, `acceptance_criteria`, `unknowns`, and `notes` fields for
|
|
956
|
-
conditional language patterns: "verify if / verify whether", "if missing / if not present /
|
|
957
|
-
if not found / if not already", "if already exists / if already included", "leave TODO /
|
|
958
|
-
add TODO / leave a note", "add if needed / create if missing", "add support if missing".
|
|
959
|
-
|
|
960
|
-
For each match, classify as a **binary-outcome item** and verify:
|
|
961
|
-
a. Positive branch: grep changed files for the implementation.
|
|
962
|
-
b. Negative branch (B-missing): grep codebase for `// TODO [CARD-ID]:` at the relevant location.
|
|
963
|
-
|
|
964
|
-
If NEITHER branch artifact exists → classify as `Missing` (not Partial) and trigger the
|
|
965
|
-
gap-resolution fix agent sub-loop immediately for these items (before continuing the checklist).
|
|
966
|
-
**Loop-counter scope**: the max-2 gap-resolution cap is tracked PER ITEM, not per phase. The
|
|
967
|
-
step-0 pre-scan and the step-5 main loop share the same per-item budget — an item that consumed
|
|
968
|
-
both retries here is NOT given two fresh retries at step 5; an item never touched here keeps its
|
|
969
|
-
full budget at step 5. This prevents both over-fixing (4 spawns) and starvation (0 retries left).
|
|
970
444
|
|
|
971
|
-
|
|
972
|
-
`conditional_items` section → flag as `Missing` (the coder must document the branch taken).
|
|
445
|
+
## Risk-signal detector (Phase 3.7 Step A — signal-logging only, NEVER gates the next step)
|
|
973
446
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
3.
|
|
447
|
+
> Questo detector vive nel core perché due consumatori lo usano in momenti diversi:
|
|
448
|
+
> la § "Trivial-card fast-lane" (a Phase 1, per classificare la card) e il modulo
|
|
449
|
+
> `references/codex-gate.md` (a Phase 3.7, Step B/C). È deterministico (grep + path
|
|
450
|
+
> match), non LLM-discrezionale, e **non gate mai** il passo successivo.
|
|
977
451
|
|
|
978
|
-
```
|
|
979
|
-
## Completeness Check — <CARD-ID>
|
|
980
|
-
| # | Requirement / Criterion | Status | Evidence |
|
|
981
|
-
|---|------------------------|--------|----------|
|
|
982
|
-
| 1 | [requirement text] | Done / Missing / Partial | [file:line or "not found"] |
|
|
983
|
-
| 2 | [acceptance criterion] | Done / Missing / Partial | [file:line or "not found"] |
|
|
984
|
-
```
|
|
985
|
-
|
|
986
|
-
4. For each item, verify by **reading the actual implementation code** — but read **narrowly** (per
|
|
987
|
-
§ "Context economy" → Targeted Reads): use the coder completion report's `evidence: file:line` as
|
|
988
|
-
the index, then `Grep` (or `Read` with a tight `offset`/`limit` around that line) for the specific
|
|
989
|
-
symbol/route/field — do NOT Read whole files into context to confirm one item. The report is your
|
|
990
|
-
index of WHERE to look; you still verify independently (do NOT trust its `status` alone), just
|
|
991
|
-
without pulling entire files inline.
|
|
992
|
-
|
|
993
|
-
**Verification depth per requirement type:**
|
|
994
|
-
- **"Create endpoint/route"** → verify: route file exists, handler has correct HTTP method,
|
|
995
|
-
request validation present, response shape matches requirement, auth middleware applied.
|
|
996
|
-
- **"Add UI component/page"** → verify: component file exists, renders the required elements,
|
|
997
|
-
handles loading/error/empty states if specified, is wired into the page/layout.
|
|
998
|
-
- **"Add field/collection"** → verify: type definition updated, field used in read AND write
|
|
999
|
-
paths, validation present if specified.
|
|
1000
|
-
- **"Integrate with X"** → verify: import exists, function is called with correct parameters,
|
|
1001
|
-
error handling present.
|
|
1002
|
-
- **Data fields completeness** → if card has `data_fields` block:
|
|
1003
|
-
- For each `status: existing` field: grep the changed files to confirm the field name is
|
|
1004
|
-
referenced in the implementation. A declared-but-unused field is a red flag (wrong name
|
|
1005
|
-
or dead code). Log in checklist as Partial if not found.
|
|
1006
|
-
- For each `status: new` field: verify the field is BOTH written (setter/creator path)
|
|
1007
|
-
AND read (getter/reader path) in the changed files.
|
|
1008
|
-
- For each `status: modified` field: verify old-name references are removed and
|
|
1009
|
-
new-name references exist.
|
|
1010
|
-
- **DB compound query** → verify: if the card has a `db_indexes` (or legacy
|
|
1011
|
-
`firestore_indexes`) field, check that EVERY listed index has been shipped to
|
|
1012
|
-
the artifact matching `stack.database`:
|
|
1013
|
-
- `firestore` → entries exist in `firestore.indexes.json` (match collection +
|
|
1014
|
-
fields + order); also grep the query code to confirm `where()` + `orderBy()`
|
|
1015
|
-
field names match the index definition exactly. Missing index = CRITICAL
|
|
1016
|
-
(runtime 500 FAILED_PRECONDITION).
|
|
1017
|
-
- `postgres`/`supabase`/`mysql`/`sqlite` → a migration file exists declaring
|
|
1018
|
-
the index (or `prisma/schema.prisma` `@@index([...])`); grep the query to
|
|
1019
|
-
confirm the column names match. Missing migration = CRITICAL (silent
|
|
1020
|
-
Seq Scan in production on hot path).
|
|
1021
|
-
- `mongodb` → `createIndex` call exists in the bootstrap script (or migration);
|
|
1022
|
-
compound field order in the call matches equality → range → sort in the query.
|
|
1023
|
-
Missing = HIGH (no immediate error, but slow aggregation under load).
|
|
1024
|
-
- `dynamodb` → the GSI/LSI is declared in the IaC table definition AND the
|
|
1025
|
-
query uses the GSI name via `IndexName`. Missing = CRITICAL (throttle on
|
|
1026
|
-
hot partition).
|
|
1027
|
-
|
|
1028
|
-
If the completion report has `items_skipped` that is not "none", immediately flag those
|
|
1029
|
-
items as Missing regardless of the agent's justification.
|
|
1030
|
-
|
|
1031
|
-
- **[UI-ONLY] Design-system conformance** → run ONLY when `briefing = "ui-expert"` from step 6b
|
|
1032
|
-
AND `features.has_design_system: true` in `baldart.config.yml`:
|
|
1033
|
-
- Grep the changed files for hardcoded design values that bypass the registry:
|
|
1034
|
-
hex colors (`#[0-9a-fA-F]{3,8}`), `rgb(`/`rgba(`, `box-shadow:` with inline
|
|
1035
|
-
offsets/blurs, `border-radius:` with px/rem literals, `font-size:` with raw
|
|
1036
|
-
px/rem (outside the type scale), `padding`/`margin` with raw px (outside the
|
|
1037
|
-
spacing scale). Each hit on a NEW or MODIFIED line = Partial — the value
|
|
1038
|
-
should come from a token, not a literal.
|
|
1039
|
-
- Verify the completion report includes the `design_system_coherence:` block
|
|
1040
|
-
required by the UI-ONLY briefing. Missing block = Missing (orchestrator
|
|
1041
|
-
cannot confirm Post-Intervention Coherence Check ran).
|
|
1042
|
-
- For each new primitive declared by the report (or detected via Grep for new
|
|
1043
|
-
components in `${paths.components_primitives}`), verify the matching
|
|
1044
|
-
`${paths.design_system}/components/<Name>.md` spec was created in the same
|
|
1045
|
-
commit. Missing spec = Partial — fix by re-spawning `ui-expert` with the
|
|
1046
|
-
narrow instruction "ship the component spec for <Name> per
|
|
1047
|
-
design-system-protocol.md".
|
|
1048
|
-
- For each token change declared by the report, verify the entry exists in
|
|
1049
|
-
`${paths.design_system}/tokens-reference.md`. Missing entry = Partial.
|
|
1050
|
-
- If `features.has_design_system: false`, log "DS conformance skipped — flag is false" and continue.
|
|
1051
|
-
|
|
1052
|
-
5. Classify each item:
|
|
1053
|
-
- **Done** — code exists AND satisfies the FULL scope of the requirement (not just partial).
|
|
1054
|
-
- **Partial** — some code exists but the criterion is not fully satisfied (e.g., UI renders but no error state, endpoint exists but wrong response shape).
|
|
1055
|
-
- **Missing** — no evidence found in the codebase, OR the coder agent explicitly skipped it.
|
|
1056
|
-
|
|
1057
|
-
**Gap resolution** (for Partial and Missing items):
|
|
1058
|
-
|
|
1059
|
-
- Spawn a **targeted fix coder agent** with:
|
|
1060
|
-
- The exact list of unimplemented items (copy the checklist rows)
|
|
1061
|
-
- The file-ownership restrictions from `## File Ownership Map`
|
|
1062
|
-
- The instruction: "Implement ONLY these missing items. Do not refactor or expand scope."
|
|
1063
|
-
- 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). Redirect each to `/tmp/<gate>-<CARD-ID>.txt` per § "Context economy" (never inline).
|
|
1064
|
-
- Re-verify each fixed item against the code — do NOT trust the agent's self-report.
|
|
1065
|
-
- 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:
|
|
1066
|
-
- Log in `## Issues & Flags`: list each unimplemented requirement.
|
|
1067
|
-
- Ask the user whether to proceed to review despite the gap or stop.
|
|
1068
|
-
- **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`.
|
|
1069
|
-
|
|
1070
|
-
5b. **API contract check**:
|
|
1071
|
-
- From `git diff --name-only "$TRUNK...HEAD"`, identify `route.ts` files that existed before this card (MODIFIED) vs newly added (NEW).
|
|
1072
|
-
- **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).
|
|
1073
|
-
- For each MODIFIED route:
|
|
1074
|
-
a. Derive the API module from path (e.g., `src/app/api/v1/booking/[id]/route.ts` → `booking`).
|
|
1075
|
-
b. Read `${paths.references_dir}/api/<module>.md` (or subdirectory match).
|
|
1076
|
-
c. Read the modified route, extract response shape from `NextResponse.json()` calls.
|
|
1077
|
-
d. Compare against documented schema.
|
|
1078
|
-
e. Flag: removed fields or changed types → `[API-CONTRACT] BREAKING` in `## Issues & Flags` (BLOCKER).
|
|
1079
|
-
Added fields only → `[API-CONTRACT] ADDITIVE` (informational).
|
|
1080
|
-
No doc found → `[API-CONTRACT] NO-DOC` (informational).
|
|
1081
|
-
|
|
1082
|
-
5c. **Reference-aliasing mutation check** (MANDATORY — deterministic detector, reference-aliasing mutation prevention).
|
|
1083
|
-
|
|
1084
|
-
Detect call sites that pair a helper invocation with in-place mutation of an input array
|
|
1085
|
-
without an identity guard. Anti-pattern (the reference-aliasing mutation family):
|
|
1086
|
-
|
|
1087
|
-
```ts
|
|
1088
|
-
const result = filterHelper(input, ...);
|
|
1089
|
-
input.length = 0; // ← wipes both input AND result when result === input
|
|
1090
|
-
input.push(...result); // ← pushes zero elements (result was just emptied)
|
|
1091
|
-
```
|
|
1092
452
|
|
|
1093
|
-
|
|
453
|
+
Run this exact bash block in the worktree. It is deterministic (grep + path match), not LLM-discretionary.
|
|
1094
454
|
|
|
1095
|
-
|
|
455
|
+
`$TRUNK` is the trunk branch resolved in Phase 0 (`git.trunk_branch`, autodetected when the key is absent — see Phase 0 step 0). `$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.** `BACKLOG_DIR` is the value of `paths.backlog_dir` from `baldart.config.yml` (fallback `backlog` when the key is absent — emit it resolved, never the literal `${paths.backlog_dir}` token, which is not valid bash). The card lookup uses `-iname` (case-insensitive) on purpose: card filenames carry uppercase prefixes (`FEAT-`/`BUG-`/`CHORE-`) but `CARD_ID` may arrive lowercased (e.g. `/new feat-0019`), and a case-sensitive `-name` would return empty silently → the card would be treated as non-existent.
|
|
1096
456
|
|
|
1097
457
|
```bash
|
|
1098
458
|
cd <worktree-path>
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
# Capture the variable name; flag for human/agent review.
|
|
1107
|
-
python3 - "$f" <<'PY'
|
|
1108
|
-
import re, sys
|
|
1109
|
-
src = open(sys.argv[1]).read().splitlines()
|
|
1110
|
-
for i, line in enumerate(src):
|
|
1111
|
-
m = re.search(r'(\w+)\.length\s*=\s*0', line)
|
|
1112
|
-
if not m: continue
|
|
1113
|
-
var = m.group(1)
|
|
1114
|
-
# Look back 5 lines for a const/let assignment from a function call returning to a different name,
|
|
1115
|
-
# then forward 3 lines for `var.push(...other)`.
|
|
1116
|
-
back = "\n".join(src[max(0,i-5):i])
|
|
1117
|
-
fwd = "\n".join(src[i+1:i+4])
|
|
1118
|
-
assign = re.search(rf'const\s+(\w+)\s*=\s*\w+\([^)]*\b{re.escape(var)}\b', back)
|
|
1119
|
-
push = re.search(rf'{re.escape(var)}\.push\(\.\.\.(\w+)\)', fwd)
|
|
1120
|
-
if assign and push and assign.group(1) == push.group(1):
|
|
1121
|
-
print(f"{sys.argv[1]}:{i+1}: ALIAS-MUTATION candidate — '{var}.length = 0' followed by '{var}.push(...{push.group(1)})' where {push.group(1)} comes from a call that received {var}")
|
|
1122
|
-
PY
|
|
1123
|
-
done
|
|
1124
|
-
```
|
|
1125
|
-
|
|
1126
|
-
For each hit, classify by reading 10 lines of context around the match:
|
|
1127
|
-
|
|
1128
|
-
- **Guarded** — an `if (<assignedName> !== <var>)` check wraps the reset+push block. SAFE. Log `[ALIAS-MUTATION] guarded` (informational, no action).
|
|
1129
|
-
- **Defensively cloned** — the helper was called with `[...var]` or `var.slice()` instead of `var`. SAFE. Log `[ALIAS-MUTATION] cloned` (informational).
|
|
1130
|
-
- **Helper always returns new array** — read every `return` in the helper. If ALL paths return `[...candidates]` / `candidates.filter(...)` / a new array literal, identity collision is impossible. SAFE. Log `[ALIAS-MUTATION] helper-immutable` (informational).
|
|
1131
|
-
- **Un-guarded** — none of the above. Flag `[ALIAS-MUTATION] BLOCKER` in `## Issues & Flags` with file:line and the captured pattern.
|
|
1132
|
-
|
|
1133
|
-
For each `[ALIAS-MUTATION] BLOCKER`:
|
|
1134
|
-
|
|
1135
|
-
- 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."
|
|
1136
|
-
- Re-run the detector after the fix. The hit MUST classify as Guarded, Cloned, or helper-immutable. Repeat **max 2 times**.
|
|
1137
|
-
- If still un-guarded after 2 loops → log in `## Issues & Flags` and ask the user.
|
|
1138
|
-
|
|
1139
|
-
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`.
|
|
1140
|
-
|
|
1141
|
-
5d. **Caller-pattern test coverage check** (MANDATORY — when card introduces or modifies an exported helper consumed by 1+ caller with in-place mutation).
|
|
1142
|
-
|
|
1143
|
-
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.
|
|
1144
|
-
|
|
1145
|
-
Required test characteristics:
|
|
1146
|
-
|
|
1147
|
-
- At least one case asserts the post-call state of the input array (e.g. `assert.strictEqual(arr.length, N)` after the helper invocation).
|
|
1148
|
-
- At least one **negative-control case** documents the failure mode that would occur if the identity guard / defensive clone were removed.
|
|
1149
|
-
|
|
1150
|
-
If the test is missing:
|
|
1151
|
-
|
|
1152
|
-
- 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).
|
|
1153
|
-
- 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`.
|
|
1154
|
-
|
|
1155
|
-
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.
|
|
1156
|
-
|
|
1157
|
-
6. **Update tracker**: phase = "2.5-completeness DONE", log result (PASS / GAPS REMAIN + count).
|
|
1158
|
-
|
|
1159
|
-
### Phase 2.5b — AC-Closure Gate (BLOCKING — Scope Closure Discipline)
|
|
1160
|
-
|
|
1161
|
-
This gate enforces `framework/agents/workflows.md § Scope Closure Discipline` at the per-card level. It runs after Phase 2.5's gap-resolution loops have settled and BEFORE Phase 2.55 (Simplify). It is non-skippable.
|
|
1162
|
-
|
|
1163
|
-
**Why this exists**: Phase 2.5's fix loops handle items an agent can implement autonomously. They do NOT handle the case where the implementer (or you, the orchestrator) decides — under context pressure or perceived complexity — that an AC is "good enough as is" or "already covered by an existing component". Burying that decision in the card YAML's `implementation_notes`, in a commit message, or in a final recap is a silent scope reduction. The decision belongs to the user.
|
|
1164
|
-
|
|
1165
|
-
**Step-by-step**:
|
|
1166
|
-
|
|
1167
|
-
1. **Update tracker**: phase = "2.5b-ac-closure".
|
|
1168
|
-
|
|
1169
|
-
2. **Build the AC Closure Ledger** — one row per `acceptance_criteria` entry from the card YAML (NOT requirements — only the AC list, because ACs are the user-facing contract):
|
|
1170
|
-
|
|
1171
|
-
```
|
|
1172
|
-
## AC Closure Ledger — <CARD-ID>
|
|
1173
|
-
| AC# | Text (verbatim) | Status | Evidence (file:line) | User-approved? |
|
|
1174
|
-
|-----|-----------------|--------|----------------------|----------------|
|
|
1175
|
-
| AC-1 | [text] | implemented | src/x.ts:42 | n/a |
|
|
1176
|
-
| AC-2 | [text] | deferred | n/a | pending |
|
|
1177
|
-
```
|
|
1178
|
-
|
|
1179
|
-
Status enum: `implemented` | `deferred`. The Phase 2.5 categories map as follows: `Done` → `implemented`; `Partial` or `Missing` (after gap-resolution exhausted retries) → `deferred`. There is no third option — an AC is either in the diff or it is being deferred.
|
|
1180
|
-
|
|
1181
|
-
3. **Rationalization scan (BLOCKING for every `deferred` row)** — read the coder's completion report and the card's `implementation_notes`. If the justification for a `deferred` AC matches any of the patterns below, classify the row as `RATIONALIZATION_NEEDS_PROOF`:
|
|
1182
|
-
|
|
1183
|
-
- "covered by <X>" / "already covers" / "existing <X> handles" / "<X> already does"
|
|
1184
|
-
- "implicit in <X>" / "no longer needed" / "redundant with <X>"
|
|
1185
|
-
- "out of scope of this card" (when the AC is clearly listed in the card YAML)
|
|
1186
|
-
|
|
1187
|
-
For each `RATIONALIZATION_NEEDS_PROOF` row, the orchestrator MUST verify by reading `<X>` and producing a line-for-line scope mapping between the AC text and the alleged coverage. The mapping goes in the tracker under `## Rationalization Verification`. If the mapping does not hold (or cannot be produced confidently), the row stays `deferred` and proceeds to Step 4 — the rationalization does NOT auto-approve the deferral.
|
|
1188
|
-
|
|
1189
|
-
4. **User gate (BLOCKING `AskUserQuestion` — one per `deferred` AC that is not pre-approved)**:
|
|
1190
|
-
|
|
1191
|
-
For each `deferred` row whose `User-approved?` is `pending`, invoke `AskUserQuestion` with:
|
|
1192
|
-
- Question: `"AC-<N> of <CARD-ID> non implementata. Testo verbatim: '<AC text>'. Motivazione dell'implementer: '<reason or 'nessuna — silent skip'>'. Come procedo?"`
|
|
1193
|
-
- Options (max 4):
|
|
1194
|
-
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.
|
|
1195
|
-
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`.
|
|
1196
|
-
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.
|
|
1197
|
-
4. **"Ferma il batch"** — halt the orchestrator, leave the worktree intact, log the reason in `## Issues & Flags`. Do NOT commit.
|
|
1198
|
-
|
|
1199
|
-
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.
|
|
1200
|
-
|
|
1201
|
-
5. **`implementation_notes` deferral audit (cheap text grep — also BLOCKING)** — before exiting the phase, scan the card YAML's `implementation_notes` field (post-edits, including any text added during this phase) for any of these phrases:
|
|
1202
|
-
|
|
1203
|
-
- `deferred` / `deferral` / `defer to`
|
|
1204
|
-
- `out of scope` / `scope cut`
|
|
1205
|
-
- `covered by` / `already handles` / `redundant`
|
|
1206
|
-
- `skipped` / `dropped`
|
|
1207
|
-
|
|
1208
|
-
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.
|
|
459
|
+
CARD_ID="<CARD-ID>"
|
|
460
|
+
BACKLOG_DIR="<value of paths.backlog_dir, or 'backlog' if the key is absent>"
|
|
461
|
+
CARD_FILE="$(find "$BACKLOG_DIR" -iname "${CARD_ID}*.yml" 2>/dev/null | head -1)"
|
|
462
|
+
# Detect what THIS card's commits changed against the trunk (post-commit), with an uncommitted fallback:
|
|
463
|
+
CHANGED="$(git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD)"
|
|
464
|
+
# High-risk path alternation from config (empty when paths.high_risk_modules is unset):
|
|
465
|
+
HIGH_RISK_RE="<alternation of paths.high_risk_modules entries, or empty>"
|
|
1209
466
|
|
|
1210
|
-
|
|
467
|
+
TRIGGERS=()
|
|
1211
468
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
469
|
+
# Trigger #1 — High-risk module (auth / permission / payment / shared scoring-or-ranking primitive)
|
|
470
|
+
# Sourced from paths.high_risk_modules — NOT a hardcoded project path.
|
|
471
|
+
if [ -n "$HIGH_RISK_RE" ]; then
|
|
472
|
+
echo "$CHANGED" | grep -qE "$HIGH_RISK_RE" \
|
|
473
|
+
&& TRIGGERS+=("#1: high-risk module (paths.high_risk_modules)")
|
|
474
|
+
else
|
|
475
|
+
echo "[DETECTOR] paths.high_risk_modules absent — path-based high-risk trigger skipped" >&2
|
|
476
|
+
fi
|
|
1215
477
|
|
|
1216
|
-
|
|
478
|
+
# Trigger #2 — Dead-code resurrection (card text + commit messages)
|
|
479
|
+
{ cat "$CARD_FILE" 2>/dev/null; git log --format=%B "$TRUNK...HEAD" 2>/dev/null; } \
|
|
480
|
+
| grep -qiE 'dead code|unreachable|resurrect' \
|
|
481
|
+
&& TRIGGERS+=("#2: Dead-code resurrection")
|
|
1217
482
|
|
|
1218
|
-
|
|
483
|
+
# Trigger #3 — Reference-aliasing mutation pattern (in-place array reset + push)
|
|
484
|
+
# Card introduces or modifies an exported helper AND a call site in the diff mutates an input
|
|
485
|
+
# array in place via `length = 0` + `push(...result)`. Even with a local identity guard, the
|
|
486
|
+
# high-risk gate runs adversarial review to confirm the contract is robust against future callers.
|
|
487
|
+
# Iterate file-by-file safely (no unquoted xargs filename expansion):
|
|
488
|
+
RESET=""; PUSH=""
|
|
489
|
+
while IFS= read -r f; do
|
|
490
|
+
[ -n "$f" ] || continue
|
|
491
|
+
C="$(git show "HEAD:$f" 2>/dev/null)" || continue
|
|
492
|
+
printf '%s' "$C" | grep -qE '\.length\s*=\s*0' && RESET=1
|
|
493
|
+
printf '%s' "$C" | grep -qE '\.push\(\s*\.\.\.' && PUSH=1
|
|
494
|
+
done <<< "$CHANGED"
|
|
495
|
+
[ -n "$RESET" ] && [ -n "$PUSH" ] \
|
|
496
|
+
&& TRIGGERS+=("#3: Reference-aliasing mutation pattern")
|
|
1219
497
|
|
|
1220
|
-
|
|
498
|
+
printf '%s\n' "${TRIGGERS[@]}"
|
|
499
|
+
```
|
|
1221
500
|
|
|
1222
|
-
1. Stop the current card's pipeline.
|
|
1223
|
-
2. Write the current state to the tracker under `## Issues & Flags` with the prefix `[CONTEXT-PRESSURE]` (which Phase 2 finished, which ACs are open, which files are dirty).
|
|
1224
|
-
3. Invoke `AskUserQuestion` with options: (a) finish remaining ACs in a fresh `/new` session that resumes from the tracker, (b) commit the complete ACs and route the rest through this gate's Step 4, (c) hand off the worktree intact to the user.
|
|
1225
501
|
|
|
1226
|
-
|
|
502
|
+
---
|
|
1227
503
|
|
|
1228
504
|
### Fix Application Log Schema (telemetry)
|
|
1229
505
|
|
|
@@ -1265,1484 +541,3 @@ Enumerated exhaustively:
|
|
|
1265
541
|
**Edge case explicit** — a mechanical append-a-row update to `CHANGELOG.md` or `ssot-registry.md` is still classified `doc` and still goes through `doc-reviewer`, never inline and never `coder`. The uniformity of the rule matters more than the cost of the individual spawn.
|
|
1266
542
|
|
|
1267
543
|
Domains NOT listed here remain governed by the per-phase rules of the corresponding phase (e.g. `simplify-*` follows Phase 2.55 inline rule).
|
|
1268
|
-
|
|
1269
|
-
### Phase 2.55 — Simplify (code cleanup before review)
|
|
1270
|
-
|
|
1271
|
-
> **Trivial fast-lane gate**: re-confirm `IS_TRIVIAL` on the ACTUAL committed diff (§ "Trivial-card fast-lane" — all 3 conditions, now including the real non-source diff check). If trivial → **SKIP this phase** AND Phase 3.5 QA + Phase 3.7 Codex; instead run the **inline mechanical gates** (`markdownlint` on changed `.md`, `lint` on lintable changed files, `build` as a sanity check — no qa-sentinel, no test suite), then proceed to Phase 3 (doc review, which DOES run) and Phase 4 (commit). Log `simplify/qa/codex: SKIPPED (trivial — non-source diff)`. If the actual diff turned out to contain a source file → NOT trivial → run this phase and the normal review path. AC-Closure (Phase 2.5b) already ran and is never skipped.
|
|
1272
|
-
|
|
1273
|
-
After completeness is verified, clean up the implementation before it reaches reviewers and E2E tests. This phase launches three parallel agents on the card's diff, then applies fixes directly.
|
|
1274
|
-
|
|
1275
|
-
**Step-by-step**:
|
|
1276
|
-
|
|
1277
|
-
1. **Update tracker**: phase = "2.55-simplify".
|
|
1278
|
-
2. Capture the current card's changes to disk — `git diff > /tmp/diff-<CARD-ID>.txt` in the worktree (**redirect, not inline** — per § "Context economy" → Diffs to disk).
|
|
1279
|
-
3. Launch **three agents in parallel** (single message). Each receives the **path** `/tmp/diff-<CARD-ID>.txt` and Reads the diff itself — do NOT paste the full diff into the prompts:
|
|
1280
|
-
|
|
1281
|
-
- **Reuse agent** — search the codebase for existing utilities/helpers that could replace newly written code. Flag duplicated functionality, inline logic that could use existing utils.
|
|
1282
|
-
- **Quality agent** — flag redundant state, parameter sprawl, copy-paste with slight variation, leaky abstractions, stringly-typed code where constants/enums exist, unnecessary JSX nesting, unnecessary comments (WHAT comments, narration, task references).
|
|
1283
|
-
- **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.
|
|
1284
|
-
|
|
1285
|
-
4. Aggregate findings from all three agents. For each finding:
|
|
1286
|
-
- **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.
|
|
1287
|
-
- **Valid AND not in a Domain-Override domain** → fix directly (apply edits inline).
|
|
1288
|
-
- **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.
|
|
1289
|
-
|
|
1290
|
-
**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>`.
|
|
1291
|
-
|
|
1292
|
-
5. After all fixes, run `npm run lint` and `npx tsc --noEmit` to confirm nothing broke (redirect to disk per § "Context economy"; surface only exit code + a bounded extract on failure).
|
|
1293
|
-
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.
|
|
1294
|
-
|
|
1295
|
-
6. **Update tracker**: phase = "2.55-simplify DONE", log count of fixes applied (or "clean — 0 fixes").
|
|
1296
|
-
If any valid finding revealed a reusable pattern or common mistake, append 1-line to `## Lessons Learned`:
|
|
1297
|
-
`SIMPLIFY: <pattern> — <file>`
|
|
1298
|
-
|
|
1299
|
-
### Phase 2.6 — End-to-End Review (BLOCKING, since v3.18.0)
|
|
1300
|
-
|
|
1301
|
-
This phase delegates to the `/e2e-review` skill — a deterministic, BLOCKING
|
|
1302
|
-
orchestrator that combines functional E2E (Playwright spec written by `coder`,
|
|
1303
|
-
executed via `playwright-skill`) with visual fidelity diff
|
|
1304
|
-
(`visual-fidelity-verifier` multimodal agent), aggregates findings under a
|
|
1305
|
-
strict severity gate, runs a bounded self-heal loop, and either passes /
|
|
1306
|
-
blocks / accepts an explicit user override.
|
|
1307
|
-
|
|
1308
|
-
The skill replaces the previous advisory pair (legacy Phase 2.6 E2E testing
|
|
1309
|
-
and Phase 2.7 visual design review). It runs by default on every UI card,
|
|
1310
|
-
auto-skips on backend-only cards, and BLOCKS the commit on gating findings.
|
|
1311
|
-
|
|
1312
|
-
#### Gate (skip the whole phase when any of the below is true)
|
|
1313
|
-
|
|
1314
|
-
| Condition | Action |
|
|
1315
|
-
|-----------|--------|
|
|
1316
|
-
| `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. |
|
|
1317
|
-
| 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.) |
|
|
1318
|
-
| 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.) |
|
|
1319
|
-
|
|
1320
|
-
#### Invocation contract
|
|
1321
|
-
|
|
1322
|
-
When the gate above passes, the orchestrator invokes `/e2e-review` in
|
|
1323
|
-
**programmatic mode**:
|
|
1324
|
-
|
|
1325
|
-
1. **Update tracker**: phase = "2.6-e2e-review".
|
|
1326
|
-
2. Spawn the skill with the payload:
|
|
1327
|
-
|
|
1328
|
-
```json
|
|
1329
|
-
{
|
|
1330
|
-
"card_id": "<CARD-ID>",
|
|
1331
|
-
"worktree_path": "<absolute worktree path>",
|
|
1332
|
-
"mode": "programmatic"
|
|
1333
|
-
}
|
|
1334
|
-
```
|
|
1335
|
-
|
|
1336
|
-
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.
|
|
1337
|
-
|
|
1338
|
-
The skill is responsible for: reading the card YAML + `test_plan`, deriving
|
|
1339
|
-
routes from the diff, walking the 4-level mockup cascade (Figma MCP →
|
|
1340
|
-
local image → compliance-only → skip), generating the Playwright spec via
|
|
1341
|
-
`coder`, executing it headless, invoking `visual-fidelity-verifier` per
|
|
1342
|
-
route, and returning a single JSON object.
|
|
1343
|
-
|
|
1344
|
-
3. Parse the returned JSON. The contract is:
|
|
1345
|
-
|
|
1346
|
-
```json
|
|
1347
|
-
{
|
|
1348
|
-
"status": "passed" | "blocked" | "overridden" | "skipped" | "error",
|
|
1349
|
-
"iterations": 0,
|
|
1350
|
-
"findings": [ ... ],
|
|
1351
|
-
"ds_drift_codes": [ "DS_TOKENS_DRIFT" | "DS_COMPONENT_STALE" | "DS_INDEX_DRIFT" ],
|
|
1352
|
-
"gaps": [ ... ],
|
|
1353
|
-
"transcript_paths": [ ... ]
|
|
1354
|
-
}
|
|
1355
|
-
```
|
|
1356
|
-
|
|
1357
|
-
#### Gating logic (BLOCKING)
|
|
1358
|
-
|
|
1359
|
-
| `status` from `/e2e-review` | Orchestrator action |
|
|
1360
|
-
|----|----|
|
|
1361
|
-
| `"passed"` | Log result in tracker. Proceed to Phase 3 (doc review + code review). |
|
|
1362
|
-
| `"skipped"` | Log skip reason. Proceed to Phase 3. |
|
|
1363
|
-
| `"overridden"` | Log override + reason in `## Issues & Flags` as `[E2E-OVERRIDE] <reason>`. Proceed to Phase 3. |
|
|
1364
|
-
| `"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. |
|
|
1365
|
-
| `"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. |
|
|
1366
|
-
|
|
1367
|
-
#### Re-run trigger (after Phase 3.7 `/codexreview`)
|
|
1368
|
-
|
|
1369
|
-
If the mandatory `/codexreview` gate in Phase 3.7 modifies any file under
|
|
1370
|
-
`${paths.app_dir}`, `${paths.components_primitives}`, or any `*.css` /
|
|
1371
|
-
`*.scss`, the orchestrator MUST re-invoke `/e2e-review` BEFORE the Phase 4
|
|
1372
|
-
commit. This protects against code-review changes that silently reintroduce
|
|
1373
|
-
visual / functional drift. The re-run reuses the same
|
|
1374
|
-
`.baldart/e2e-review/<CARD-ID>/` state directory and starts from Phase 3
|
|
1375
|
-
of the skill (skipping plan extraction and mockup cascade).
|
|
1376
|
-
|
|
1377
|
-
#### Tracker output
|
|
1378
|
-
|
|
1379
|
-
Append to `## Current Card` and (on completion) carry into `## Completed Cards`:
|
|
1380
|
-
|
|
1381
|
-
```
|
|
1382
|
-
e2e-review: <status> | iterations: <N> | findings: <X critical, Y major, Z minor> | drift: [<codes>] | tolerance: <strict|balanced|lenient>
|
|
1383
|
-
```
|
|
1384
|
-
|
|
1385
|
-
#### Out of scope for this phase
|
|
1386
|
-
|
|
1387
|
-
- Mockup re-design (the skill never modifies the mockup — only the
|
|
1388
|
-
implementation).
|
|
1389
|
-
- Code review or doc review (those remain Phase 3 / 3.7 responsibilities).
|
|
1390
|
-
- Unit-test execution (that is `qa-sentinel`).
|
|
1391
|
-
- Visual polish beyond gating findings (advisory Minor findings under
|
|
1392
|
-
balanced/lenient tolerance are logged but not actioned).
|
|
1393
|
-
|
|
1394
|
-
#### Legacy cards
|
|
1395
|
-
|
|
1396
|
-
Cards written before v3.18.0 (without a `test_plan` block) still work — the
|
|
1397
|
-
skill's Phase 1 falls back to deriving Gherkin scenarios from
|
|
1398
|
-
`acceptance_criteria` directly. The mockup cascade gracefully degrades when
|
|
1399
|
-
`links.design` is missing.
|
|
1400
|
-
|
|
1401
|
-
---
|
|
1402
|
-
|
|
1403
|
-
### Phase 3 — Doc Review & Sync (code review handled by mandatory Phase 3.7 gate)
|
|
1404
|
-
|
|
1405
|
-
> **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).
|
|
1406
|
-
|
|
1407
|
-
> **Deferral gate (since v4.7.0 — enumerated, `review_profile`-driven)**: SKIP per-card doc-review and defer it to the **Final Review F.3 doc-reviewer** (which runs over the entire batch) when the card is **`review_profile == light` AND its committed diff touches NO documentation file** (no `.md`, no path under `${paths.references_dir}`, no data-model/ssot/api doc). These are small code changes with no doc surface of their own; their only doc concern is drift, which the batch-wide Final doc-reviewer catches. Log `doc-review: DEFERRED to Final FULL gate (light, no doc files in diff)` and proceed to Phase 3.5. **KEEP per-card doc-review** for: `balanced`/`deep` cards, ANY card whose diff touches a doc file (the change IS doc-relevant), and trivial cards (doc-review is their primary gate — § "Trivial-card fast-lane", unchanged). Never defer "for time" — the only enumerated reason is `light + non-doc diff`.
|
|
1408
|
-
|
|
1409
|
-
12. **Update tracker**: phase = "3-doc-review".
|
|
1410
|
-
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):
|
|
1411
|
-
```bash
|
|
1412
|
-
git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD
|
|
1413
|
-
```
|
|
1414
|
-
Use the output to build this block:
|
|
1415
|
-
```
|
|
1416
|
-
## Doc Sync Context
|
|
1417
|
-
|
|
1418
|
-
### Changed code files (for freshness mapping):
|
|
1419
|
-
[list all code files changed — src/, scripts/, etc.]
|
|
1420
|
-
|
|
1421
|
-
### Invariant checklist (Linking Protocol — docs/guides/linking-protocol-rollout-v1.md):
|
|
1422
|
-
- [ ] New route.ts added? → ${paths.references_dir}/api/<module>.md + api/index.md count
|
|
1423
|
-
- [ ] New page.tsx added? → ${paths.references_dir}/ui/<domain>.md + ui/index.md Route Summary
|
|
1424
|
-
- [ ] New persistence-layer {entity} ({collection|table|item} per `stack.database`)? → ${paths.references_dir}/data-model.md + the entity's reference doc per project convention (`collections/<domain>.md`, `tables/<domain>.md`, etc.)
|
|
1425
|
-
- [ ] Compound query needing a multi-attribute index? → the matching index artifact MUST be staged in the same commit, per `stack.database`: `firestore.indexes.json` (firestore), migration file or Prisma `@@index` (SQL), `createIndex` script (mongo), GSI/LSI in IaC (dynamodb)
|
|
1426
|
-
- [ ] Backlog card set to DONE? → ${paths.references_dir}/ssot-registry.md entry
|
|
1427
|
-
- [ ] New external dependency? → agents/architecture.md External Dependencies list
|
|
1428
|
-
- [ ] Card has `documentation_impact` field? → verify each listed doc is updated
|
|
1429
|
-
- [ ] New `process.env.VAR` added? → entry in `${paths.references_dir}/env-vars.md` (name, scope, required, feature/card, default)
|
|
1430
|
-
- [ ] Last usage of `process.env.VAR` removed? → mark `status: deprecated` in `${paths.references_dir}/env-vars.md` with the date
|
|
1431
|
-
- [ ] 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`
|
|
1432
|
-
- [ ] Card has an `env_vars` field populated? → verify each entry is tracked in `${paths.references_dir}/env-vars.md`
|
|
1433
|
-
|
|
1434
|
-
### Related docs to check (per convention map):
|
|
1435
|
-
- [derive from FRESHNESS_MAP: src/app/api/** → ${paths.references_dir}/api/; src/lib/booking/** → booking.md etc.]
|
|
1436
|
-
```
|
|
1437
|
-
|
|
1438
|
-
Invoke the **doc-reviewer** agent in **audit-and-apply mode** (single invocation — it both finds the gaps AND fixes them, per `doc-reviewer.md` § Constraints), passing the Doc Sync Context:
|
|
1439
|
-
```
|
|
1440
|
-
Doc Sync Context:
|
|
1441
|
-
[paste the Doc Sync Context block built above]
|
|
1442
|
-
|
|
1443
|
-
Instructions for doc-reviewer:
|
|
1444
|
-
- You OWN the `doc` domain end-to-end: audit AND apply the fixes in THIS invocation.
|
|
1445
|
-
Do NOT defer doc writes to another agent — you are the agent with the doc-invariant
|
|
1446
|
-
contract and the full context. Write the missing/stale docs directly.
|
|
1447
|
-
- Set freshness_status: fresh and last_verified_from_code: <today's date> on any doc you touch
|
|
1448
|
-
- Check each invariant in the checklist above and fix any that are unmet
|
|
1449
|
-
- Update any doc in "Related docs to check" that should be marked stale/fresh
|
|
1450
|
-
- Run your standard doc audit on all changed files and apply the corrections
|
|
1451
|
-
- **Spec/docs-drift → bug lens (MANDATORY since v3.35.0)**: flag any place where the
|
|
1452
|
-
implementation contradicts a documented contract/spec in a way that can cause incorrect
|
|
1453
|
-
behavior (response shape diverging from `api/<module>.md`, field semantics diverging from
|
|
1454
|
-
`data-model.md`, etc.). This lens was previously exclusive to `/codexreview` agent #4; the
|
|
1455
|
-
per-card Phase 3.7 gate now skips that duplicate (lean mode), so THIS pass MUST carry it.
|
|
1456
|
-
A doc-drift→bug finding whose root cause is in CODE (not the doc) is the ONE thing
|
|
1457
|
-
doc-reviewer does NOT fix itself — report it with the conflicting code location + the doc
|
|
1458
|
-
it violates, and the orchestrator routes it to the `security`/code fix path as appropriate.
|
|
1459
|
-
```
|
|
1460
|
-
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.
|
|
1461
|
-
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.
|
|
1462
|
-
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.)
|
|
1463
|
-
16. Run `npm run lint` and `npx tsc --noEmit` (when `stack.language` includes typescript) to verify nothing broke (redirect to disk per § "Context economy"). 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).
|
|
1464
|
-
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.
|
|
1465
|
-
If doc-reviewer found a recurring gap, append 1-line to `## Lessons Learned`:
|
|
1466
|
-
`DOC: <pattern>`
|
|
1467
|
-
|
|
1468
|
-
### Phase 3.5 — QA Validation
|
|
1469
|
-
|
|
1470
|
-
18. **Update tracker**: phase = "3.5-qa".
|
|
1471
|
-
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).
|
|
1472
|
-
20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
|
|
1473
|
-
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.
|
|
1474
|
-
21b. **If profile is BALANCED (since v4.7.0 — deferral to Final, enumerated `review_profile`-driven)**: SKIP per-card qa-sentinel and **defer the test suite to the Final Review F.3 qa-sentinel** (which runs the FULL suite + build + audit over the entire batch — the unconditional merge gate). Phase 2 step 8 already ran lint/tsc/test/build on this card's diff. **Exception — risk escalation runs FULL per-card anyway**: if the Phase 3.7 Step A detector matched any high-risk trigger on this card's diff (auth/permission/payment/schema/migration/API-contract), do NOT defer — run qa-sentinel at FULL here for fail-fast. Log `QA balanced deferred to Final FULL gate (no risk escalation)` or `QA balanced escalated to FULL (risk drift: <trigger>)`. ⚠️ Most `feature`/`enhancement` cards are `balanced` (Rule C), so a balanced-only batch first runs the suite at the Final gate; the merge gate stays safe (Final = full suite over the whole batch). Proceed to Phase 4 when deferred.
|
|
1475
|
-
22. **If profile is DEEP (or BALANCED escalated by risk drift — see 21b)**: invoke the **`qa-sentinel`** agent (subagent_type: `qa-sentinel`) via Task tool with the following context:
|
|
1476
|
-
|
|
1477
|
-
```
|
|
1478
|
-
Run QA gates on card <CARD-ID> at the tier dictated by the QA profile below (do NOT default to FULL).
|
|
1479
|
-
You are a MECHANICAL GATE-RUNNER: run the gates, return a PASS/FAIL gate table + confidence.
|
|
1480
|
-
Do NOT read source files to analyze logic, do NOT emit a BLOCKER/MAJOR/MINOR severity taxonomy,
|
|
1481
|
-
do NOT do collateral-impact analysis, and do NOT write tests.
|
|
1482
|
-
|
|
1483
|
-
Context:
|
|
1484
|
-
- Worktree path: <worktree-path> — `cd` into it before running any gate
|
|
1485
|
-
- Branch: <branch-name>
|
|
1486
|
-
- Changed files: <list from implementation phase>
|
|
1487
|
-
- QA profile: [deep | balanced-escalated]
|
|
1488
|
-
|
|
1489
|
-
Tier contract: deep → FULL suite. A BALANCED card only reaches this step when risk drift
|
|
1490
|
-
escalated it (step 21b) — run it at FULL too (the escalation reason is the fail-fast signal).
|
|
1491
|
-
A non-escalated balanced card never reaches here (its suite is deferred to the Final FULL gate
|
|
1492
|
-
per step 21b). File count never escalates.
|
|
1493
|
-
|
|
1494
|
-
E2E is NOT your job (run by the /e2e-review skill in Phase 2.6) — do NOT run Playwright.
|
|
1495
|
-
Run the gates: lint, tsc (when stack.language includes typescript), test (per tier), build, markdownlint.
|
|
1496
|
-
Do NOT verify acceptance criteria (Phase 2.5 already did this).
|
|
1497
|
-
Do NOT analyze code for bugs/patterns (the per-card /codexreview gate in Phase 3.7 does this).
|
|
1498
|
-
|
|
1499
|
-
Write the gate results + verdict to: /qa/<CARD-ID>.md
|
|
1500
|
-
Report should be under 40 lines.
|
|
1501
|
-
Return verdict: PASS or FAIL (+ the per-gate table).
|
|
1502
|
-
```
|
|
1503
|
-
|
|
1504
|
-
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.
|
|
1505
|
-
24. **If QA verdict is FAIL** (one or more gates failed):
|
|
1506
|
-
- 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.
|
|
1507
|
-
- After coder fixes, re-invoke `qa-sentinel` in the same mode to re-validate. Repeat up to **2 times**.
|
|
1508
|
-
- If still FAIL after 2 retries: log in `## Issues & Flags` and **ask the user** whether to proceed or stop.
|
|
1509
|
-
- The commit in Phase 4 MUST NOT happen until QA verdict is PASS (or user explicitly overrides).
|
|
1510
|
-
- **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`.
|
|
1511
|
-
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.
|
|
1512
|
-
|
|
1513
|
-
### Phase 3.7 — Pre-Merge Codex Review Gate (MANDATORY — UNCONDITIONAL)
|
|
1514
|
-
|
|
1515
|
-
**This gate runs for EVERY card with code to review before the Phase 4 commit.** A per-card `/codexreview` MUST run BEFORE the Phase 4 commit, regardless of file paths or perceived risk. The historical conditional High-Risk Path detector is preserved below — but only as a **signal-logging step** to record *which* triggers matched in the tracker. It NEVER suppresses the `/codexreview` invocation. Even if zero triggers match, `/codexreview` runs.
|
|
1516
|
-
|
|
1517
|
-
> **Single carve-out — `IS_TRIVIAL` fast-lane (since v4.6.0)**: a card that is `IS_TRIVIAL` on its ACTUAL committed diff (`review_profile=skip` + non-source diff + 0 Step-A triggers — § "Trivial-card fast-lane") **skips this gate**, because there is no code for Codex to review. Its adversarial coverage is carried by the SAME unconditional **Final-review FULL gate** the `light` path already relies on (it runs Codex over the entire batch diff, including every trivial card's files, before merge). This is NOT a `time budget` skip — it is the deterministic `IS_TRIVIAL` gate reason, and the guard means a single source file in the diff flips the card back onto this gate. Log `codex-review: SKIPPED (trivial — non-source diff; covered by Final FULL gate)`.
|
|
1518
|
-
|
|
1519
|
-
**Rationale**: leaving the gate conditional caused it to be silently skipped on the majority of cards, defeating the AGENTS.md "MUST run BEFORE merge" requirement. The gate itself is unconditional — what varies is its DEPTH (`light` vs `full`). The protection against a missed blocker on a "low-risk" path (BUG-0530-class regressions) is carried by two mechanisms, not by an always-on per-card Codex pass: (1) the Step A detector escalates any risky diff to `full` per-card, and (2) the unconditional **Final-review FULL gate** runs Codex adversarial over the entire batch diff before merge. So `light` can safely run `code-reviewer` + FP-gate only (since v3.38.0) without weakening the merge gate.
|
|
1520
|
-
|
|
1521
|
-
#### Step A — Detect (signal-logging only, NEVER gates the next step)
|
|
1522
|
-
|
|
1523
|
-
Run this exact bash block in the worktree. It is deterministic (grep + path match), not LLM-discretionary.
|
|
1524
|
-
|
|
1525
|
-
`$TRUNK` is the trunk branch resolved in Phase 0 (`git.trunk_branch`, autodetected when the key is absent — see Phase 0 step 0). `$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.** `BACKLOG_DIR` is the value of `paths.backlog_dir` from `baldart.config.yml` (fallback `backlog` when the key is absent — emit it resolved, never the literal `${paths.backlog_dir}` token, which is not valid bash). The card lookup uses `-iname` (case-insensitive) on purpose: card filenames carry uppercase prefixes (`FEAT-`/`BUG-`/`CHORE-`) but `CARD_ID` may arrive lowercased (e.g. `/new feat-0019`), and a case-sensitive `-name` would return empty silently → the card would be treated as non-existent.
|
|
1526
|
-
|
|
1527
|
-
```bash
|
|
1528
|
-
cd <worktree-path>
|
|
1529
|
-
CARD_ID="<CARD-ID>"
|
|
1530
|
-
BACKLOG_DIR="<value of paths.backlog_dir, or 'backlog' if the key is absent>"
|
|
1531
|
-
CARD_FILE="$(find "$BACKLOG_DIR" -iname "${CARD_ID}*.yml" 2>/dev/null | head -1)"
|
|
1532
|
-
# Detect what THIS card's commits changed against the trunk (post-commit), with an uncommitted fallback:
|
|
1533
|
-
CHANGED="$(git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD)"
|
|
1534
|
-
# High-risk path alternation from config (empty when paths.high_risk_modules is unset):
|
|
1535
|
-
HIGH_RISK_RE="<alternation of paths.high_risk_modules entries, or empty>"
|
|
1536
|
-
|
|
1537
|
-
TRIGGERS=()
|
|
1538
|
-
|
|
1539
|
-
# Trigger #1 — High-risk module (auth / permission / payment / shared scoring-or-ranking primitive)
|
|
1540
|
-
# Sourced from paths.high_risk_modules — NOT a hardcoded project path.
|
|
1541
|
-
if [ -n "$HIGH_RISK_RE" ]; then
|
|
1542
|
-
echo "$CHANGED" | grep -qE "$HIGH_RISK_RE" \
|
|
1543
|
-
&& TRIGGERS+=("#1: high-risk module (paths.high_risk_modules)")
|
|
1544
|
-
else
|
|
1545
|
-
echo "[DETECTOR] paths.high_risk_modules absent — path-based high-risk trigger skipped" >&2
|
|
1546
|
-
fi
|
|
1547
|
-
|
|
1548
|
-
# Trigger #2 — Dead-code resurrection (card text + commit messages)
|
|
1549
|
-
{ cat "$CARD_FILE" 2>/dev/null; git log --format=%B "$TRUNK...HEAD" 2>/dev/null; } \
|
|
1550
|
-
| grep -qiE 'dead code|unreachable|resurrect' \
|
|
1551
|
-
&& TRIGGERS+=("#2: Dead-code resurrection")
|
|
1552
|
-
|
|
1553
|
-
# Trigger #3 — Reference-aliasing mutation pattern (in-place array reset + push)
|
|
1554
|
-
# Card introduces or modifies an exported helper AND a call site in the diff mutates an input
|
|
1555
|
-
# array in place via `length = 0` + `push(...result)`. Even with a local identity guard, the
|
|
1556
|
-
# high-risk gate runs adversarial review to confirm the contract is robust against future callers.
|
|
1557
|
-
# Iterate file-by-file safely (no unquoted xargs filename expansion):
|
|
1558
|
-
RESET=""; PUSH=""
|
|
1559
|
-
while IFS= read -r f; do
|
|
1560
|
-
[ -n "$f" ] || continue
|
|
1561
|
-
C="$(git show "HEAD:$f" 2>/dev/null)" || continue
|
|
1562
|
-
printf '%s' "$C" | grep -qE '\.length\s*=\s*0' && RESET=1
|
|
1563
|
-
printf '%s' "$C" | grep -qE '\.push\(\s*\.\.\.' && PUSH=1
|
|
1564
|
-
done <<< "$CHANGED"
|
|
1565
|
-
[ -n "$RESET" ] && [ -n "$PUSH" ] \
|
|
1566
|
-
&& TRIGGERS+=("#3: Reference-aliasing mutation pattern")
|
|
1567
|
-
|
|
1568
|
-
printf '%s\n' "${TRIGGERS[@]}"
|
|
1569
|
-
```
|
|
1570
|
-
|
|
1571
|
-
#### Step B — Log detector result (never skips)
|
|
1572
|
-
|
|
1573
|
-
Log the detector output in the tracker for traceability. **This step never short-circuits Step C — `/codexreview` runs unconditionally regardless of whether `TRIGGERS` is empty or populated.**
|
|
1574
|
-
|
|
1575
|
-
- If `TRIGGERS` is empty: log `## Pre-Merge Codex Review: no high-risk triggers matched (gate still runs unconditionally)` and proceed to Step C.
|
|
1576
|
-
- If `TRIGGERS` is non-empty: log the matched triggers (see Step C step 1) and proceed to Step C.
|
|
1577
|
-
|
|
1578
|
-
#### Step C — Invoke per-card `/codexreview` (ALWAYS)
|
|
1579
|
-
|
|
1580
|
-
For EVERY card (no conditional skip — the gate ALWAYS runs; only its DEPTH varies):
|
|
1581
|
-
|
|
1582
|
-
0. **Select the Codex review profile (deterministic — Review Profile Selector)** by mapping the
|
|
1583
|
-
card's review profile (read from the card's `review_profile` field per the QA Profile Selector
|
|
1584
|
-
above — since v3.38.0; fallback-computed only for legacy cards) and the Step A detector:
|
|
1585
|
-
- **`light`** ⟺ the card's profile ∈ {`skip`, `light`} **AND** Step A matched **zero**
|
|
1586
|
-
high-risk triggers.
|
|
1587
|
-
- **`full`** ⟺ otherwise — i.e. the card's profile ∈ {`balanced`, `deep`}, **OR** any Step A
|
|
1588
|
-
trigger matched.
|
|
1589
|
-
|
|
1590
|
-
**Escalation-only invariant (since v3.38.0)**: the Step A detector runs on the ACTUAL diff and
|
|
1591
|
-
can only ever **escalate** `light` → `full` (a high-risk path surfaced at implementation time
|
|
1592
|
-
that the card's authored profile didn't anticipate). It can NEVER downgrade `full` → `light`.
|
|
1593
|
-
The card's `review_profile` is the deterministic floor; the diff detector is the safety net on
|
|
1594
|
-
top of it.
|
|
1595
|
-
|
|
1596
|
-
`light` is **NOT** a skip: `/codexreview` still runs `code-reviewer` + the Step 3 false-positive
|
|
1597
|
-
gate. **Since v3.38.0 the per-card Codex adversarial pass is NO LONGER run at `light`** — it is the
|
|
1598
|
-
prerogative of `full` and of the final cross-check. `light` drops the Codex adversarial pass AND the
|
|
1599
|
-
breadth agents (qa-sentinel, api-perf-cost-auditor, doc-reviewer) AND Step 3.5 CoVe — leaving exactly
|
|
1600
|
-
`code-reviewer` + FP-gate, the cheap per-card pass that yields the early feedback worth having on a
|
|
1601
|
-
0-trigger, QA-light diff. `full` is unchanged (Codex adversarial + the full agent set, minus the
|
|
1602
|
-
duplicate doc-reviewer).
|
|
1603
|
-
**Where the BUG-0530 invariant now lives.** Pre-v3.38.0 the per-card Codex adversarial was the
|
|
1604
|
-
"never miss a blocker on a low-risk path" guard. Two mechanisms now carry that guarantee instead,
|
|
1605
|
-
so dropping it from `light` is safe:
|
|
1606
|
-
1. **Escalation-only (Step A)** — any high-risk trigger on the ACTUAL diff promotes `light` → `full`,
|
|
1607
|
-
so genuinely risky paths (auth/payment/permission/schema/…) STILL get per-card Codex adversarial.
|
|
1608
|
-
Only a 0-trigger, authored-`light` card defers it.
|
|
1609
|
-
2. **Final-review FULL gate (since v3.37.0)** — the **Final review ALWAYS runs a single FULL
|
|
1610
|
-
`/codexreview` over the entire batch diff before merge** (no N=1 skip, no scope reduction — see
|
|
1611
|
-
"Final review → Final-review FULL gate"), and FULL includes Codex adversarial. So every line of
|
|
1612
|
-
every `light` card receives Codex adversarial at least once before merge.
|
|
1613
|
-
Net effect: `light` per-card = early `code-reviewer` feedback; the Codex adversarial review is paid
|
|
1614
|
-
once, at the final batch gate (or per-card the moment a risk trigger fires). To put per-card Codex
|
|
1615
|
-
back on `light`, re-add agent #5 to the `light` branch of `/codexreview` Step -0.5.
|
|
1616
|
-
|
|
1617
|
-
Then dump the card diff (reviewer grounding) and write the lean contract `/codexreview` consumes:
|
|
1618
|
-
```bash
|
|
1619
|
-
cd <worktree-path>
|
|
1620
|
-
# $TRUNK = the trunk branch resolved in Phase 0 (git.trunk_branch)
|
|
1621
|
-
git diff "$TRUNK...HEAD" -- <card files from ownership map> > /tmp/diff-<CARD-ID>.txt 2>/dev/null \
|
|
1622
|
-
|| git diff HEAD~1..HEAD > /tmp/diff-<CARD-ID>.txt
|
|
1623
|
-
```
|
|
1624
|
-
Write `/tmp/codexreview-lean-<CARD-ID>.json`:
|
|
1625
|
-
```json
|
|
1626
|
-
{ "profile": "light|full", "arch_baseline_path": "/tmp/arch-baseline-<CARD-ID>.md",
|
|
1627
|
-
"diff_summary_path": "/tmp/diff-<CARD-ID>.txt", "skip_doc_reviewer": true,
|
|
1628
|
-
"skip_api_perf_auditor": true }
|
|
1629
|
-
```
|
|
1630
|
-
`skip_doc_reviewer` is ALWAYS true: Phase 3 already ran `doc-reviewer` on this diff (with the
|
|
1631
|
-
spec/docs-drift→bug lens since v3.35.0), so `/codexreview` agent #3 would be a duplicate.
|
|
1632
|
-
`skip_api_perf_auditor` is ALWAYS true (since v4.7.0): the per-card api-perf/cost pass is deferred
|
|
1633
|
-
to the **Final Review F.3 api-perf-cost-auditor** (batch-wide), so `/codexreview` agent #2 would be
|
|
1634
|
-
a duplicate of the final sweep. (At `full` `/codexreview` would otherwise spawn it; at `light` it is
|
|
1635
|
-
already dropped.)
|
|
1636
|
-
|
|
1637
|
-
1. **Log gate invocation** in the tracker under `## Pre-Merge Codex Review`:
|
|
1638
|
-
|
|
1639
|
-
```
|
|
1640
|
-
## Pre-Merge Codex Review
|
|
1641
|
-
- Triggered: unconditional (mandatory pre-merge gate)
|
|
1642
|
-
- Profile: light | full — reason: <review_profile=<skip|light|balanced|deep> (from card | computed); triggers=0 | trigger #N matched (escalated light→full)>
|
|
1643
|
-
- Matched high-risk triggers: <list from detector, or "none">
|
|
1644
|
-
- Action: invoking /codexreview <CARD-ID> (per-card, pre-merge gate; lean contract written)
|
|
1645
|
-
```
|
|
1646
|
-
|
|
1647
|
-
2. **Invoke `/codexreview`** for the single card via the Skill tool:
|
|
1648
|
-
|
|
1649
|
-
```
|
|
1650
|
-
Skill: codexreview
|
|
1651
|
-
args: <CARD-ID>
|
|
1652
|
-
```
|
|
1653
|
-
|
|
1654
|
-
`/codexreview` Step -0.5 consumes `/tmp/codexreview-lean-<CARD-ID>.json`: reuses the Phase-1
|
|
1655
|
-
architecture baseline (no re-spawn), drops the duplicate doc-reviewer, and for `profile: light`
|
|
1656
|
-
also drops qa-sentinel + api-perf-cost-auditor + **the Codex adversarial pass** + Step 3.5 CoVe
|
|
1657
|
-
(since v3.38.0). `code-reviewer` + Step 3 FP-gate + Step 4 report ALWAYS run. (`full` = standard
|
|
1658
|
-
pipeline incl. Codex adversarial, minus the duplicate doc-reviewer.)
|
|
1659
|
-
|
|
1660
|
-
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:
|
|
1661
|
-
- Verified BLOCKER count
|
|
1662
|
-
- Verified HIGH count
|
|
1663
|
-
- 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".
|
|
1664
|
-
|
|
1665
|
-
4. **Apply fix sub-loop** (mirror of Phase 3.5 retry pattern):
|
|
1666
|
-
- 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.)
|
|
1667
|
-
- 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**.
|
|
1668
|
-
- 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.
|
|
1669
|
-
- **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.
|
|
1670
|
-
|
|
1671
|
-
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.
|
|
1672
|
-
|
|
1673
|
-
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.
|
|
1674
|
-
|
|
1675
|
-
#### Why deterministic detector + agent pipeline
|
|
1676
|
-
|
|
1677
|
-
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.
|
|
1678
|
-
|
|
1679
|
-
**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.
|
|
1680
|
-
|
|
1681
|
-
### Phase 4 — Commit (in worktree, NO merge yet)
|
|
1682
|
-
|
|
1683
|
-
> 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.
|
|
1684
|
-
|
|
1685
|
-
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 (redirect to disk per § "Context economy").
|
|
1686
|
-
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.
|
|
1687
|
-
- **IMPORTANT — explicit staging**: NEVER use `git add -A` or `git add .`. Always stage files by explicit name:
|
|
1688
|
-
```bash
|
|
1689
|
-
cd <worktree-path>
|
|
1690
|
-
# List changed files
|
|
1691
|
-
git diff --name-only
|
|
1692
|
-
git ls-files --others --exclude-standard
|
|
1693
|
-
# Stage only the files this card touched (explicit names)
|
|
1694
|
-
git add src/path/to/file1.ts src/path/to/file2.ts ...
|
|
1695
|
-
# Commit directly — NO stash in worktrees
|
|
1696
|
-
git commit -m "[CARD-ID] Brief description"
|
|
1697
|
-
```
|
|
1698
|
-
- **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.
|
|
1699
|
-
- **If commit fails**:
|
|
1700
|
-
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.
|
|
1701
|
-
1. **Check for stale COMMIT_LOCK first** — parallel agents and crashed processes leave stale lock files. Always clear before retry:
|
|
1702
|
-
```bash
|
|
1703
|
-
rm -f <main-repo>/.git/worktrees/<worktree-name>/COMMIT_LOCK 2>/dev/null
|
|
1704
|
-
```
|
|
1705
|
-
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.
|
|
1706
|
-
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.
|
|
1707
|
-
- The Claude Code pre-commit hook automatically skips for worktree commits (Husky handles checks natively in the worktree).
|
|
1708
|
-
28. **Mark card DONE (MANDATORY — do NOT skip)**:
|
|
1709
|
-
a. Edit the backlog YAML (`${paths.backlog_dir}/<CARD-ID>.yml`): set `status: DONE`, add `completed_date: <today>`.
|
|
1710
|
-
b. Add implementation notes summarizing what was built.
|
|
1711
|
-
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 `${paths.backlog_dir}/` without a corresponding ssot-registry update. Always include ssot-registry.md in the same commit as the backlog YAML.
|
|
1712
|
-
d. **Verify the write**: re-read the YAML file and confirm `status: DONE` is present. If not, retry the edit.
|
|
1713
|
-
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.
|
|
1714
|
-
29. **Update tracker**: move card to `## Completed Cards` with commit hash(es), summary, flags, **and `card_status: DONE (verified)`**. **→ Visibility**: TaskUpdate this card's spine task → `completed` (strip any live phase suffix) and emit a Progress Bar (card change) per § "Progress Visibility".
|
|
1715
|
-
|
|
1716
|
-
### Sub-agent failure protocol (since v3.28.3)
|
|
1717
|
-
|
|
1718
|
-
If any sub-agent **crashes or errors** during any phase, follow this 4-step protocol. The pre-v3.28.3 wording ("attempt the work yourself directly") was being used as a shortcut to bypass delegation rules even when no agent had crashed — that escape valve is closed.
|
|
1719
|
-
|
|
1720
|
-
1. **Log the failure** in the tracker with the full error trace (under `## Issues & Flags`, prefix `[AGENT-CRASH]`).
|
|
1721
|
-
2. **Retry the same agent once**. Transient errors (network, rate-limit, race) are common; a single retry resolves most.
|
|
1722
|
-
3. **If retry fails AND the fix is in a domain-override domain** (`doc`, `security`, `migration` — see "Domain-Override Domains" sub-section): **STOP the pipeline**, log in `## Issues & Flags`, and invoke `AskUserQuestion` with options (a) skip the finding, (b) hand off to user, (c) escalate to a different agent type. **NEVER** fall through to inline orchestrator apply for these domains. The whole point of delegation here is that the orchestrator does not have the right system prompt — bypassing on crash defeats the rule.
|
|
1723
|
-
4. **If retry fails AND the fix is non-domain-override**: orchestrator MAY apply inline, but MUST log a Fix Application Log row with `applied_by=orchestrator-fallback` + `reason=<agent>-crash-retry-failed` so the telemetry surfaces frequency. If this happens often for the same agent, that agent's reliability is the problem, not the protocol.
|
|
1724
|
-
|
|
1725
|
-
Never block the pipeline indefinitely — recover and continue per the rules above. AskUserQuestion in step 3 is bounded by normal user response time.
|
|
1726
|
-
|
|
1727
|
-
### Phase 5 — Context Clean & Continue
|
|
1728
|
-
30. Archive the card from Active Code Context in `${paths.references_dir}/project-status.md`.
|
|
1729
|
-
31. **CONTEXT HYGIENE**: After updating the tracker, stop referencing this card's details. From this point forward do NOT pull this card's code, file contents, or review findings back into your messages — the tracker summary is the only carry-over; if you need a detail, Read the tracker (or the on-disk findings/gate file) at the point you need it. NOTE: this is a *reference-hygiene* instruction, not token reclamation — a prompt cannot make the model "forget" (see § "Context economy"). The real lever is upstream: because the § "Context economy" rules kept this card's bulk (gate logs, diffs, whole files, baselines) OUT of your inline context in the first place, there is little to carry over. If the harness auto-compacts at a card boundary, recover via the tracker per § "Context Tracking".
|
|
1730
|
-
32. **Update tracker**: clear `## Current Card`, move to next pending card.
|
|
1731
|
-
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**.
|
|
1732
|
-
|
|
1733
|
-
---
|
|
1734
|
-
|
|
1735
|
-
## Final review (after all cards)
|
|
1736
|
-
|
|
1737
|
-
> **Primary code reviewer: Codex (a non-Anthropic frontier model, via `codex-companion.mjs`)** — cross-model validation with built-in FP filtering.
|
|
1738
|
-
> Claude `code-reviewer` is the automatic fallback if Codex is unavailable.
|
|
1739
|
-
> The `/codexreview` command remains available for standalone reviews on demand.
|
|
1740
|
-
|
|
1741
|
-
Once ALL cards are committed in the worktree:
|
|
1742
|
-
|
|
1743
|
-
> **Final-review FULL gate (since v3.37.0 — supersedes the v3.35.0 scope-reduction)** — because
|
|
1744
|
-
> Phase 3.7 may now run a card at `light` depth, the per-card pass can NO LONGER be assumed to have
|
|
1745
|
-
> full-reviewed every card. The final review is therefore the **unconditional safety gate that makes
|
|
1746
|
-
> the Phase 3.7 `light` profile safe**: it ALWAYS runs a single FULL `/codexreview` (full agent set)
|
|
1747
|
-
> over the **ENTIRE batch diff** before merge — **no N=1 skip, no cross-card scope reduction**. Every
|
|
1748
|
-
> line of every card — including any reviewed at `light` in Phase 3.7 — receives a full-depth Codex
|
|
1749
|
-
> review at least once before merge.
|
|
1750
|
-
>
|
|
1751
|
-
> - Run Steps F.1–F.5 for **EVERY batch, including N=1**. Nothing here is skipped.
|
|
1752
|
-
> - `review_scope_files` = the **FULL union** of all touched files across all cards (F.1 step 4 —
|
|
1753
|
-
> NEVER reduced to the cross-card subset).
|
|
1754
|
-
> - F.3 invokes the full reviewer set (Codex + doc-reviewer + api-perf-cost-auditor + qa-sentinel)
|
|
1755
|
-
> over that union; F.5 runs the final build.
|
|
1756
|
-
>
|
|
1757
|
-
> Rationale: this re-introduces the post-batch full pass that v3.35.0 de-duplicated away. That
|
|
1758
|
-
> de-dup assumed Phase 3.7 had already full-reviewed every card — an assumption broken the moment
|
|
1759
|
-
> `light` became selectable. The cost of one full batch-diff review is the deliberate price of the
|
|
1760
|
-
> per-card `light` speed-up (explicit maintainer decision, v3.37.0).
|
|
1761
|
-
|
|
1762
|
-
### Step F.1 — Resolve scope
|
|
1763
|
-
|
|
1764
|
-
**→ Visibility (batch transition)**: all cards are committed. TaskUpdate `Final review` → `in_progress` and emit a Progress Bar per § "Progress Visibility". Mark `Final review` → `completed` when F.5 finishes (fixes applied, build green).
|
|
1765
|
-
|
|
1766
|
-
1. **Read the tracker file** to get the full picture: card IDs, files changed, commit hashes.
|
|
1767
|
-
2. Gather git evidence in the worktree:
|
|
1768
|
-
```bash
|
|
1769
|
-
cd <worktree-path>
|
|
1770
|
-
git diff --name-only <base-branch>...HEAD
|
|
1771
|
-
```
|
|
1772
|
-
3. Read each card's backlog YAML to collect `acceptance_criteria`, `files_likely_touched`.
|
|
1773
|
-
4. Build `review_scope_files` as the **FULL union** of card-indicated files + git-touched files
|
|
1774
|
-
across ALL cards in the batch. **Since v3.37.0 this union is NEVER reduced** (the v3.35.0
|
|
1775
|
-
cross-card scope-reduction is removed) — the final review is a full-depth pass over the entire
|
|
1776
|
-
batch diff, so cards reviewed at `light` in Phase 3.7 still get a guaranteed full review before
|
|
1777
|
-
merge. Record the union in the tracker; downstream F.3 reviews it in full.
|
|
1778
|
-
|
|
1779
|
-
### Step F.2 — Architecture baseline
|
|
1780
|
-
|
|
1781
|
-
5. **Reuse per-card baselines before re-spawning (dedup).** Phase 1 step 5b already persisted one
|
|
1782
|
-
`/tmp/arch-baseline-<CARD-ID>.md` per card. Before spawning `codebase-architect` for the batch
|
|
1783
|
-
scope, check whether every card in the batch already has a readable baseline file:
|
|
1784
|
-
```bash
|
|
1785
|
-
MISSING=()
|
|
1786
|
-
for c in <ALL-CARD-IDS>; do [ -s "/tmp/arch-baseline-$c.md" ] || MISSING+=("$c"); done
|
|
1787
|
-
printf '%s\n' "${MISSING[@]}"
|
|
1788
|
-
```
|
|
1789
|
-
- **All present** → do NOT re-spawn the architect for the full batch. Set `${ARCH_BASELINE_PATHS}`
|
|
1790
|
-
to the newline-separated **list of `/tmp/arch-baseline-<CARD-ID>.md` paths** (they already cover
|
|
1791
|
-
every touched file across the batch) — do NOT read or concatenate their contents inline (per
|
|
1792
|
-
§ "Context economy" → pass paths, not concatenations; Codex Reads them on demand). Proceed to F.3.
|
|
1793
|
-
Log `f.2-arch: reused N per-card baselines (no re-spawn)` in the tracker. This avoids the N+1
|
|
1794
|
-
architect invocations the per-card persistence was designed to prevent.
|
|
1795
|
-
- **Any missing** (a card was added late, or a baseline was purged) → invoke **codebase-architect**
|
|
1796
|
-
ONCE over the batch scope to map existing architecture, critical patterns, and high-risk code
|
|
1797
|
-
paths for regression. Persist its output to `/tmp/arch-baseline-batch-<FIRST-CARD-ID>.md` and set
|
|
1798
|
-
`${ARCH_BASELINE_PATHS}` to that single path. Log `f.2-arch: re-spawned (missing baselines: <list>)`. Do NOT spawn
|
|
1799
|
-
the architect more than once for the batch — it is the single grounding context for all
|
|
1800
|
-
downstream review agents.
|
|
1801
|
-
|
|
1802
|
-
### Step F.3 — Codex deep code review (primary) + Claude agents (support)
|
|
1803
|
-
|
|
1804
|
-
> **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.
|
|
1805
|
-
|
|
1806
|
-
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 redirected to the file with `> "$REVIEW_FILE" 2>&1`, so it fills as Codex runs and is complete when the background task finishes — no inline `tee` copy, per § "Context economy"). Combining `run_in_background: true` with `--wait` would block the shell and defeat the parallelism — do NOT pass `--wait` here.
|
|
1807
|
-
|
|
1808
|
-
```bash
|
|
1809
|
-
REVIEW_FILE="/tmp/codexreview-batch-<FIRST-CARD-ID>-<SESSION-ID>.md" && \
|
|
1810
|
-
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)" && \
|
|
1811
|
-
[ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" > "$REVIEW_FILE" && exit 1; \
|
|
1812
|
-
node "$CODEX_SCRIPT" task "
|
|
1813
|
-
Run a deep multi-agent code review for these backlog cards. This is a post-implementation
|
|
1814
|
-
review — the code is already written and committed. Your job is to find bugs, regressions,
|
|
1815
|
-
security issues, and quality problems.
|
|
1816
|
-
|
|
1817
|
-
Cards to review (read each file):
|
|
1818
|
-
${CARD_PATHS}
|
|
1819
|
-
|
|
1820
|
-
Files changed (review ALL of these):
|
|
1821
|
-
${REVIEW_SCOPE_FILES}
|
|
1822
|
-
|
|
1823
|
-
Architecture baseline files (read each — they hold file paths, type signatures, patterns, high-risk paths):
|
|
1824
|
-
${ARCH_BASELINE_PATHS}
|
|
1825
|
-
|
|
1826
|
-
Follow the /codexreview protocol:
|
|
1827
|
-
1. For each card, read its backlog YAML for acceptance_criteria and entrypoints.
|
|
1828
|
-
2. Read every changed file in full.
|
|
1829
|
-
3. Check for: functional bugs, logic flaws, regressions, cross-card inconsistencies,
|
|
1830
|
-
security issues (auth gaps, input validation, multi-tenant isolation),
|
|
1831
|
-
performance issues (unbounded reads, N+1, missing pagination),
|
|
1832
|
-
missing error handling on external boundaries.
|
|
1833
|
-
4. For each finding, return:
|
|
1834
|
-
- finding_id: <CARD-ID>-F###
|
|
1835
|
-
- title: short description
|
|
1836
|
-
- severity: BLOCKER | HIGH | MEDIUM | LOW
|
|
1837
|
-
- confidence: 0-100
|
|
1838
|
-
- evidence: exact file:line + code quote
|
|
1839
|
-
- minimal_fix_direction: what to change
|
|
1840
|
-
5. Run mandatory false-positive check: for each finding, ask 'What is the strongest
|
|
1841
|
-
argument this is a false positive?' Suppress if the FP argument is convincing.
|
|
1842
|
-
6. Classify surviving findings as VERIFIED, FALSE_POSITIVE, or NEEDS_MANUAL_CONFIRMATION.
|
|
1843
|
-
|
|
1844
|
-
Return ONLY verified findings. If zero verified bugs: state 'No verified bugs found.'
|
|
1845
|
-
" > "$REVIEW_FILE" 2>&1
|
|
1846
|
-
```
|
|
1847
|
-
|
|
1848
|
-
**Variable interpolation** (build the command string before execution):
|
|
1849
|
-
- `${CARD_PATHS}`: newline-separated list of backlog YAML paths
|
|
1850
|
-
- `${REVIEW_SCOPE_FILES}`: newline-separated list from Step F.1
|
|
1851
|
-
- `${ARCH_BASELINE_PATHS}`: newline-separated list of per-card baseline file paths from Step F.2 (Codex Reads them on demand — do NOT inline their contents)
|
|
1852
|
-
|
|
1853
|
-
7. **In parallel with Codex**, launch Claude support agents (single message):
|
|
1854
|
-
|
|
1855
|
-
| Agent | `subagent_type` | Focus | Output |
|
|
1856
|
-
|-------|-----------------|-------|--------|
|
|
1857
|
-
| **doc-reviewer** | `doc-reviewer` | Cross-card doc consistency, ssot-registry completeness, invariants | Findings: `finding_id`, `title`, `severity`, `confidence`, `evidence`, `minimal_fix_direction` |
|
|
1858
|
-
| **api-perf-cost-auditor** | `api-perf-cost-auditor` | API/data/performance/cost defects (skip if no API/data files in scope) | Same findings schema |
|
|
1859
|
-
| **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. |
|
|
1860
|
-
|
|
1861
|
-
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.
|
|
1862
|
-
|
|
1863
|
-
**Fan-out completion barrier (BLOCKING before F.4).** The three Claude agents write to a shared
|
|
1864
|
-
findings pool that F.4 step 9 fans in. Before F.4 reads ANY finding, you MUST have collected the
|
|
1865
|
-
return value of ALL THREE Task invocations from step 7 (doc-reviewer, api-perf-cost-auditor,
|
|
1866
|
-
qa-sentinel) — never start the merge while a Task is still in flight. Because step 7 launches all
|
|
1867
|
-
three in a single message, the harness returns when all three complete; do NOT proceed to step 9
|
|
1868
|
-
on a partial set. (The Codex background task has its OWN barrier — step 8 below polls `$REVIEW_FILE`
|
|
1869
|
-
for completion. The two barriers are independent: wait for BOTH the three Claude Tasks AND the
|
|
1870
|
-
Codex background task before merging.)
|
|
1871
|
-
|
|
1872
|
-
### Step F.4 — Collect & merge findings
|
|
1873
|
-
|
|
1874
|
-
8. **Read Codex findings** from `$REVIEW_FILE` after the background command completes (the background
|
|
1875
|
-
task was launched with `timeout: 600000` in step 6 — that 10-min window is the max wait).
|
|
1876
|
-
- If file exists and contains findings → use as **primary code review source**.
|
|
1877
|
-
- If file is empty, missing, or contains `CODEX_NOT_FOUND` → **fallback**: spawn `code-reviewer`
|
|
1878
|
-
agent (subagent_type: `code-reviewer`) with the same scope and instructions. Log fallback
|
|
1879
|
-
reason in tracker: `"Codex unavailable — fallback to Claude code-reviewer"`.
|
|
1880
|
-
- **TIMED_OUT branch:** if the 10-min window elapses and `$REVIEW_FILE` still has no terminal
|
|
1881
|
-
output (no findings block and no `CODEX_NOT_FOUND`), treat the Codex pass as **TIMED_OUT** — do
|
|
1882
|
-
NOT block the merge gate waiting indefinitely and do NOT leave the task silently "in-progress".
|
|
1883
|
-
Log `f.3-codex: TIMED_OUT` in `## Issues & Flags` and take the SAME `code-reviewer` fallback as
|
|
1884
|
-
the unavailable case, so the final merge gate still gets a full code review.
|
|
1885
|
-
|
|
1886
|
-
9. **Merge all findings** (Codex + Claude agents) into a consolidated list.
|
|
1887
|
-
- Codex findings are already FP-validated (Step F.3 protocol includes it).
|
|
1888
|
-
- 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.)
|
|
1889
|
-
- Classify: `VERIFIED` | `FALSE_POSITIVE` | `NEEDS_MANUAL_CONFIRMATION`.
|
|
1890
|
-
- `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.
|
|
1891
|
-
|
|
1892
|
-
### Step F.5 — Apply fixes and final build
|
|
1893
|
-
|
|
1894
|
-
10. **Persist verified findings** to `/tmp/batch-final-review-<FIRST-CARD-ID>.md`.
|
|
1895
|
-
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"):
|
|
1896
|
-
- **`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.
|
|
1897
|
-
- **`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.
|
|
1898
|
-
- **All remaining findings** (other code, perf, test) → invoke the **coder** agent once to apply them in a single pass.
|
|
1899
|
-
Run in the order doc-reviewer → coder (or skip either if its partition is empty). Pass only the verified findings, not false positives.
|
|
1900
|
-
12. Run final build: `npm run lint && npx tsc --noEmit && npm run build` (redirect each to `/tmp/final-<gate>.txt` per § "Context economy"; surface only exit code + bounded extract on failure).
|
|
1901
|
-
If any check fails, apply self-healing retry loop (up to 3 times).
|
|
1902
|
-
13. **Update tracker** with final review results:
|
|
1903
|
-
- Review engine: Codex (a non-Anthropic frontier model, resolved at runtime by `codex-companion.mjs`) (primary) | Claude code-reviewer (fallback)
|
|
1904
|
-
- Total findings raised / verified / false positives / needs-manual
|
|
1905
|
-
- Fixes applied count
|
|
1906
|
-
- Build status (pass/fail + retry count)
|
|
1907
|
-
- Highest severity found
|
|
1908
|
-
- **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.)
|
|
1909
|
-
|
|
1910
|
-
### Step F.6 — Post-review wrap-up (SSOT summary, sync, hand-off to Phase 6)
|
|
1911
|
-
|
|
1912
|
-
> 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.
|
|
1913
|
-
|
|
1914
|
-
1. **SSOT & Documentation Activity** (MANDATORY — run BEFORE merge):
|
|
1915
|
-
|
|
1916
|
-
Summarize all documentation and SSOT updates performed during the batch:
|
|
1917
|
-
|
|
1918
|
-
```
|
|
1919
|
-
## Aggiornamenti SSOT & Documentazione
|
|
1920
|
-
|
|
1921
|
-
### Documenti aggiornati
|
|
1922
|
-
- `${paths.references_dir}/api/<module>.md` — N nuovi endpoint aggiunti
|
|
1923
|
-
- `${paths.references_dir}/ui/<domain>.md` — N nuove route aggiunte
|
|
1924
|
-
- `${paths.references_dir}/data-model.md` — N nuove collection
|
|
1925
|
-
- `${paths.references_dir}/ssot-registry.md` — N entry aggiornate/create
|
|
1926
|
-
- `${paths.references_dir}/project-status.md` — contesto aggiornato
|
|
1927
|
-
|
|
1928
|
-
### ADR creati
|
|
1929
|
-
- `${paths.adrs_dir}/ADR-YYYYMMDD-<slug>.md` — [titolo] (o "Nessun ADR creato")
|
|
1930
|
-
```
|
|
1931
|
-
|
|
1932
|
-
2. **Knowledge Base Sync** (OPTIONAL — only if the project has an external knowledge corpus, e.g. an Obsidian vault, Confluence space, or Notion workspace):
|
|
1933
|
-
|
|
1934
|
-
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).
|
|
1935
|
-
|
|
1936
|
-
3. **Proceed to Phase 6** (post-batch merge & cleanup).
|
|
1937
|
-
4. Present a **single summary report** to the user per card (and a batch summary at the end):
|
|
1938
|
-
- **Files changed** (short list per card)
|
|
1939
|
-
- **Test results** (new tests + existing tests count, pass rate at each iteration)
|
|
1940
|
-
- **Build/lint status** (pass + retry count if any)
|
|
1941
|
-
- **Fix cycles** (total number of self-healing retries across phases)
|
|
1942
|
-
- **Final review** (findings: N raised / M verified / K false positives | fixes applied: N | highest severity)
|
|
1943
|
-
- **UX testing** (PASS/FAIL/SKIP | test file path if written)
|
|
1944
|
-
- **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.
|
|
1945
|
-
- **Issues needing user attention** (anything unresolved, partially wired, or flagged)
|
|
1946
|
-
- **Commit hashes** (from tracker)
|
|
1947
|
-
- **Merge commit hash** (from Phase 6)
|
|
1948
|
-
- **Card status reconciliation** (Phase 6b: N cards verified DONE, K force-updated)
|
|
1949
|
-
- **Worktree cleanup status** (success/failed)
|
|
1950
|
-
- **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)
|
|
1951
|
-
- Overall implementation status
|
|
1952
|
-
|
|
1953
|
-
4b. **Next Steps & Launch Command** (MANDATORY section — always present):
|
|
1954
|
-
|
|
1955
|
-
Check for remaining not-yet-DONE cards in the same epic group (match "not DONE",
|
|
1956
|
-
not a hard-coded status value — see the `status enum` SSOT in REGISTRY.md):
|
|
1957
|
-
|
|
1958
|
-
```bash
|
|
1959
|
-
# Find parent epic's cards that are NOT yet DONE (TODO | READY | IN_PROGRESS | BLOCKED)
|
|
1960
|
-
grep -l "parent: <EPIC-ID>" ${paths.backlog_dir}/*.yml \
|
|
1961
|
-
| xargs grep -L "status: DONE"
|
|
1962
|
-
```
|
|
1963
|
-
|
|
1964
|
-
Present the section:
|
|
1965
|
-
|
|
1966
|
-
```
|
|
1967
|
-
## Prossimi Passi
|
|
1968
|
-
|
|
1969
|
-
### Lancio implementazione (copia e incolla)
|
|
1970
|
-
```
|
|
1971
|
-
/new FEAT-XXXX-05 FEAT-XXXX-06 FEAT-XXXX-07
|
|
1972
|
-
```
|
|
1973
|
-
|
|
1974
|
-
### Card rimanenti nell'epic
|
|
1975
|
-
| Card | Titolo | Status | Gruppo parallelo |
|
|
1976
|
-
|------|--------|--------|-----------------|
|
|
1977
|
-
| FEAT-XXXX-05 | [title] | TODO | 2 |
|
|
1978
|
-
| FEAT-XXXX-06 | [title] | TODO | 2 |
|
|
1979
|
-
|
|
1980
|
-
### Card completate in questa sessione
|
|
1981
|
-
| Card | Titolo | Commit |
|
|
1982
|
-
|------|--------|--------|
|
|
1983
|
-
| FEAT-XXXX-01 | [title] | abc1234 |
|
|
1984
|
-
| FEAT-XXXX-02 | [title] | def5678 |
|
|
1985
|
-
```
|
|
1986
|
-
|
|
1987
|
-
If ALL cards in the epic are DONE:
|
|
1988
|
-
```
|
|
1989
|
-
## Prossimi Passi
|
|
1990
|
-
|
|
1991
|
-
Tutte le card dell'epic **FEAT-XXXX** sono state completate.
|
|
1992
|
-
Pronto per il deploy: `/deploy` o `git push origin <trunk branch>` (il `git.trunk_branch` configurato)
|
|
1993
|
-
```
|
|
1994
|
-
|
|
1995
|
-
5. **Proceed to Phase 7** (production readiness checklist).
|
|
1996
|
-
|
|
1997
|
-
---
|
|
1998
|
-
|
|
1999
|
-
## Phase 6 — Post-batch merge & cleanup (delegated to worktree-manager skill)
|
|
2000
|
-
|
|
2001
|
-
**→ Visibility (batch transition)**: TaskUpdate `Merge & cleanup` → `in_progress` and emit a Progress Bar per § "Progress Visibility". Mark it → `completed` at the end of Phase 6c (merge done, worktree removed, workspace reconciled).
|
|
2002
|
-
|
|
2003
|
-
After the final review passes AND all cards are committed in the worktree, delegate the entire merge and cleanup to the **worktree-manager** skill (`/mw` in programmatic mode):
|
|
2004
|
-
|
|
2005
|
-
1. **BEFORE invoking /mw** — verify no uncommitted files remain in the worktree:
|
|
2006
|
-
```bash
|
|
2007
|
-
cd <worktree-path>
|
|
2008
|
-
git status --porcelain
|
|
2009
|
-
```
|
|
2010
|
-
If ANY uncommitted files exist (staged, unstaged, or untracked), commit them NOW with `[safety] Auto-commit remaining files before merge`. Do NOT proceed to `/mw` with a dirty worktree — files WILL be lost during rebase.
|
|
2011
|
-
2. Invoke `/mw` with:
|
|
2012
|
-
- The worktree path and branch from the tracker
|
|
2013
|
-
- `checksAlreadyPassed: true` (final review + QA already validated the build)
|
|
2014
|
-
- All card IDs for the commit message
|
|
2015
|
-
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.
|
|
2016
|
-
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.
|
|
2017
|
-
5. **If post-merge build fails** → the skill STOPs and keeps the worktree intact for investigation.
|
|
2018
|
-
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).
|
|
2019
|
-
|
|
2020
|
-
### Phase 6b — Backlog Card Status Reconciliation (MANDATORY — ZERO TOLERANCE)
|
|
2021
|
-
|
|
2022
|
-
**This gate runs IMMEDIATELY after Phase 6 merge completes, BEFORE presenting any summary to the user. It is NON-SKIPPABLE.**
|
|
2023
|
-
|
|
2024
|
-
The most common failure mode is leaving cards IN_PROGRESS after merge. This creates SSOT drift and confuses downstream agents (codebase-architect, doc-reviewer). This gate prevents that.
|
|
2025
|
-
|
|
2026
|
-
**Steps:**
|
|
2027
|
-
|
|
2028
|
-
1. **Read the tracker file** to get the full list of card IDs in the batch.
|
|
2029
|
-
2. **For EACH card in the batch**, read its backlog YAML (`${paths.backlog_dir}/<CARD-ID>.yml`) and check the `status` field:
|
|
2030
|
-
- If `status: DONE` → OK, skip.
|
|
2031
|
-
- If `status` is anything else (`IN_PROGRESS`, `READY`, `TODO`, etc.) → **FORCE UPDATE to DONE immediately**.
|
|
2032
|
-
3. **Early exit — all cards already DONE**: if step 2 found ALL cards are already `status: DONE`, skip steps 4-5 entirely. Log in the tracker:
|
|
2033
|
-
```
|
|
2034
|
-
## Phase 6b — Status Reconciliation
|
|
2035
|
-
Cards checked: N
|
|
2036
|
-
Already DONE: N (all cards marked DONE by coder agents)
|
|
2037
|
-
Force-updated to DONE: 0
|
|
2038
|
-
Reconciliation commit: not needed
|
|
2039
|
-
```
|
|
2040
|
-
Proceed directly to step 6.
|
|
2041
|
-
4. **Force update procedure** for non-DONE cards:
|
|
2042
|
-
```bash
|
|
2043
|
-
# In the MAIN repo (not worktree — worktree is already cleaned up)
|
|
2044
|
-
cd <main-repo-path>
|
|
2045
|
-
```
|
|
2046
|
-
Edit the backlog YAML: set `status: DONE`, add `completed_date: <today>`, add implementation note: `"Marked DONE by post-merge reconciliation gate (Phase 6b)"`.
|
|
2047
|
-
5. **If ANY card was force-updated**: commit in the main repo with these precautions:
|
|
2048
|
-
a. **Clear stale COMMIT_LOCK** (common when coder agents crash or timeout):
|
|
2049
|
-
```bash
|
|
2050
|
-
# Remove any stale COMMIT_LOCK from main repo or worktrees
|
|
2051
|
-
rm -f <main-repo-path>/.git/COMMIT_LOCK 2>/dev/null
|
|
2052
|
-
find <main-repo-path>/.git/worktrees -name COMMIT_LOCK -delete 2>/dev/null || true
|
|
2053
|
-
```
|
|
2054
|
-
b. **Stage backlog YAMLs AND related docs** (pre-commit hook requires doc updates):
|
|
2055
|
-
```bash
|
|
2056
|
-
# Stage only the force-updated backlog YAMLs
|
|
2057
|
-
git add ${paths.backlog_dir}/CARD-001.yml ${paths.backlog_dir}/CARD-002.yml
|
|
2058
|
-
# If ssot-registry.md was modified during the batch, stage it too
|
|
2059
|
-
# (doc-freshness hook blocks commits that touch ${paths.backlog_dir}/ without ssot-registry.md)
|
|
2060
|
-
git diff --name-only ${paths.references_dir}/ssot-registry.md && git add ${paths.references_dir}/ssot-registry.md || true
|
|
2061
|
-
```
|
|
2062
|
-
c. **Commit with explicit file list**:
|
|
2063
|
-
```bash
|
|
2064
|
-
git commit -m "[BATCH] Mark cards DONE — post-merge reconciliation"
|
|
2065
|
-
```
|
|
2066
|
-
d. **If commit fails due to pre-commit hook** (lint-staged, doc-freshness): check the error.
|
|
2067
|
-
- If "no staged files" → all changes were already committed. Log as "not needed".
|
|
2068
|
-
- If doc-freshness requires ssot-registry.md → update its `last_verified_from_code` date, stage it, and retry.
|
|
2069
|
-
- If COMMIT_LOCK → re-run step 5a and retry.
|
|
2070
|
-
- Do NOT retry more than 2 times. Log the failure and move on.
|
|
2071
|
-
6. **Update tracker** with reconciliation results:
|
|
2072
|
-
```
|
|
2073
|
-
## Phase 6b — Status Reconciliation
|
|
2074
|
-
Cards checked: N
|
|
2075
|
-
Already DONE: M
|
|
2076
|
-
Force-updated to DONE: K [list card IDs]
|
|
2077
|
-
Reconciliation commit: <hash> (or "not needed")
|
|
2078
|
-
```
|
|
2079
|
-
7. **HALT condition**: if a card cannot be updated (e.g., file read error, YAML parse error), log it in `## Issues & Flags` and continue with the remaining cards. Report the failure in the final summary.
|
|
2080
|
-
|
|
2081
|
-
**Why this exists**: Agents frequently skip the DONE marking in Phase 4 (step 27) due to context compaction, commit failures that interrupt the flow, or team mode where Step D.6 gets lost. This gate is the safety net that catches ALL of these cases.
|
|
2082
|
-
|
|
2083
|
-
### Phase 6c — Workspace Hygiene Post-merge (BLOCKING — non-skippable)
|
|
2084
|
-
|
|
2085
|
-
**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.
|
|
2086
|
-
|
|
2087
|
-
**Auto Mode does NOT override this phase.** Every `AskUserQuestion` below is non-bypassable.
|
|
2088
|
-
|
|
2089
|
-
**Steps:**
|
|
2090
|
-
|
|
2091
|
-
1. **Fetch remote state**:
|
|
2092
|
-
```bash
|
|
2093
|
-
git -C "$MAIN" fetch origin --quiet
|
|
2094
|
-
```
|
|
2095
|
-
|
|
2096
|
-
2. **Parse `mw-docs` sync markers** — scan the captured stdout from every `/mw` invocation in this batch (kept in the tracker under `## Worktree Merges`):
|
|
2097
|
-
- **`[SYNC-DEFERRED] main repo HEAD=<branch>`** (main repo HEAD ≠ `$TRUNK`) — surface via `AskUserQuestion`:
|
|
2098
|
-
- Question: `"Una o più merge worktree hanno deferito la sincronizzazione di local $TRUNK (main repo HEAD non era $TRUNK). Come riconcilio adesso?"`
|
|
2099
|
-
- Options: `[Ora HEAD è $TRUNK → ff-pull adesso]` / `[Lascia deferred (riconcilio io manualmente)]` / `[Mostra dettagli e fammi decidere]`.
|
|
2100
|
-
- **`[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`:
|
|
2101
|
-
- Question: `"Il $TRUNK locale non si è sincronizzato: <dettaglio dal marker>. Come chiudo?"`
|
|
2102
|
-
- Options: `[Committa tu adesso (descrivi cosa)]` / `[Lo gestisco io — chiudi senza sync locale]` / `[Mostrami il diff e decidiamo]`.
|
|
2103
|
-
- **No marker** — `/mw` fast-forwarded (or auto-reconciled the framework telemetry log); nothing to parse.
|
|
2104
|
-
|
|
2105
|
-
3. **Clean-tree assertion (BLOCKING)**:
|
|
2106
|
-
```bash
|
|
2107
|
-
git -C "$MAIN" status --porcelain
|
|
2108
|
-
```
|
|
2109
|
-
If non-empty AND no Phase 0 stash is pending → invoke `AskUserQuestion`:
|
|
2110
|
-
- Question: `"Main repo ha modifiche non committate dopo il batch (non c'era stash di Phase 0). Cosa faccio?"`
|
|
2111
|
-
- Options: `[Mostrami il diff e fammi decidere]` / `[Stash adesso con label baldart-post-batch-<timestamp>]` / `[Lascia così (lo gestisco io)]` / `[Halt]`.
|
|
2112
|
-
|
|
2113
|
-
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.
|
|
2114
|
-
```bash
|
|
2115
|
-
read BEHIND AHEAD <<< "$(git -C "$MAIN" rev-list --left-right --count "origin/$TRUNK...$TRUNK")"
|
|
2116
|
-
```
|
|
2117
|
-
Compute `$GENUINE_AHEAD` / `$GENUINE_LIST` / `$FW_SKIPPED` with the **exact same reclassification loop as Phase 0 step 4** (framework-management commits — subtree merges into `.framework/`, `baldart update`/`add` chores, `.framework/`-only commits — are auto-ignored, NOT orphan commits). Then branch on `$BEHIND` and `$GENUINE_AHEAD`:
|
|
2118
|
-
- **`BEHIND=0` and `GENUINE_AHEAD=0`** — synchronized. If `$FW_SKIPPED > 0`, log `Divergence: $FW_SKIPPED framework-management commits ahead (auto-ignored)` and proceed. No `AskUserQuestion`.
|
|
2119
|
-
- **Ahead only (`GENUINE_AHEAD > 0`, genuine unpushed commits)** — invoke `AskUserQuestion`:
|
|
2120
|
-
- Question: `"Local $TRUNK ha $GENUINE_AHEAD commit genuini non pushati su origin/$TRUNK al termine del batch (esclusi $FW_SKIPPED di gestione framework). Lista: <git show -s --oneline $GENUINE_LIST>. Cosa faccio?"`
|
|
2121
|
-
- 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]`.
|
|
2122
|
-
- 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.
|
|
2123
|
-
- **Behind only (`BEHIND > 0`, `GENUINE_AHEAD=0`)** — invoke `AskUserQuestion`:
|
|
2124
|
-
- Question: `"Local $TRUNK è behind origin/$TRUNK di $BEHIND commit (qualcuno ha pushato durante il batch). Faccio ff-pull adesso?"`
|
|
2125
|
-
- Options: `[Fast-forward pull]` / `[Lascia behind (lo gestisco io)]`.
|
|
2126
|
-
- **Diverged both ways (`BEHIND > 0` and `GENUINE_AHEAD > 0`)** — invoke `AskUserQuestion`:
|
|
2127
|
-
- Question: `"Local $TRUNK è diverged ($BEHIND behind, $GENUINE_AHEAD genuine ahead). Servono entrambe le riconciliazioni. Come procedo?"`
|
|
2128
|
-
- Options: `[Rebase local $TRUNK su origin/$TRUNK]` / `[Mostrami i commit locali e decidiamo]` / `[Halt]`.
|
|
2129
|
-
|
|
2130
|
-
5. **Restore Phase 0 stash (if any)** — read the tracker for `## Workspace Snapshot: <message-label>`:
|
|
2131
|
-
- If the snapshot is `dirty-tree override` → skip restore, log "user retained dirty-tree responsibility".
|
|
2132
|
-
- 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:
|
|
2133
|
-
```bash
|
|
2134
|
-
REF="$(git -C "$MAIN" stash list | grep -F "<message-label>" | head -1 | cut -d: -f1)"
|
|
2135
|
-
[ -n "$REF" ] && git -C "$MAIN" stash pop "$REF" \
|
|
2136
|
-
|| echo "stash '<message-label>' not found — was it already restored?"
|
|
2137
|
-
```
|
|
2138
|
-
On conflict, do NOT silent-drop — invoke `AskUserQuestion`:
|
|
2139
|
-
- Question: `"Restore dello stash di Phase 0 ha generato conflitti. Lo stash è ancora presente (NON eliminato). Come procedo?"`
|
|
2140
|
-
- Options: `[Lascia lo stash + apri istruzioni per merge manuale]` / `[Mostrami il conflitto inline]` / `[Halt]`.
|
|
2141
|
-
|
|
2142
|
-
6. **Log and exit**:
|
|
2143
|
-
```
|
|
2144
|
-
## Phase 6c — Workspace Hygiene Post-merge
|
|
2145
|
-
Status: PASS
|
|
2146
|
-
Clean-tree: <yes | resolved: stashed | user-retained>
|
|
2147
|
-
Divergence (local…origin/$TRUNK): <0\t0 | resolved: pushed/cherry-picked/ff-pulled/rebased>
|
|
2148
|
-
Sync-deferred markers: <none | reconciled | user-retained>
|
|
2149
|
-
Phase 0 snapshot restore: <n/a | popped clean | conflict-deferred-to-user>
|
|
2150
|
-
Completed: <timestamp>
|
|
2151
|
-
```
|
|
2152
|
-
If any step ended in HALT, set `Status: HALT` and report — Phase 7 must NOT start with an unclean main repo unless the user explicitly chose `[Lascia così]`.
|
|
2153
|
-
|
|
2154
|
-
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.
|
|
2155
|
-
|
|
2156
|
-
### Fail-safe rules (enforced by worktree-manager skill)
|
|
2157
|
-
- **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.
|
|
2158
|
-
- 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).
|
|
2159
|
-
- Never force push to the trunk. `--force-with-lease` on feature branches after rebase is allowed.
|
|
2160
|
-
- Never delete a branch before successful merge verification.
|
|
2161
|
-
- Never remove a worktree before confirming the trunk is stable post-merge.
|
|
2162
|
-
- Stop execution immediately if any command fails.
|
|
2163
|
-
|
|
2164
|
-
---
|
|
2165
|
-
|
|
2166
|
-
## Phase 7 — Production Readiness Checklist
|
|
2167
|
-
|
|
2168
|
-
After Phase 6 completes (or after the final summary report if Phase 6 is deferred), present a **Production Readiness Checklist** — a clear list of all manual or infrastructure actions required to launch the implemented changes in production.
|
|
2169
|
-
|
|
2170
|
-
### How to detect items
|
|
2171
|
-
|
|
2172
|
-
Scan ALL files changed across the batch (use the tracker's completed cards + `git diff` against the base branch) and check for the items below.
|
|
2173
|
-
|
|
2174
|
-
**The "Action to report" column shows the command for the deployment target
|
|
2175
|
-
matching `stack.deployment` in `baldart.config.yml`.** When `stack.deployment`
|
|
2176
|
-
is empty, infer from `stack.database` + presence of config files
|
|
2177
|
-
(`vercel.json`, `firebase.json`, `wrangler.toml`, `fly.toml`) and fall back to
|
|
2178
|
-
asking the user.
|
|
2179
|
-
|
|
2180
|
-
| Category | Detection signal | Action to report (per `stack.deployment`) |
|
|
2181
|
-
|----------|-----------------|-------------------------------------------|
|
|
2182
|
-
| **Database indexes** | New/modified index config file (`firestore.indexes.json`, SQL migration with `CREATE INDEX`, `prisma migrate` artifact, `db.createIndex` call, CDK/Terraform GSI) | firebase: `firebase deploy --only firestore:indexes`; vercel+postgres: run migrations during deploy; aws+dynamodb: apply CDK/Terraform; generic: run the project's migration command |
|
|
2183
|
-
| **Persistence-layer access rules** | New/modified `firestore.rules`, Supabase RLS migration, Mongo validator, DynamoDB IAM policy | firebase: `firebase deploy --only firestore:rules`; supabase: `supabase db push`; aws+dynamodb: apply IAM via CDK/Terraform |
|
|
2184
|
-
| **Storage access rules** | New/modified `storage.rules` or equivalent bucket policy | firebase: `firebase deploy --only storage:rules`; aws: apply S3 bucket policy; gcp: apply GCS IAM |
|
|
2185
|
-
| **Environment variables** | New `process.env.*` references not in the base branch, new entries in `.env.example` or `.env.local` | 1. Add to the deployment platform (Vercel/Firebase/Cloudflare/AWS Param Store) — list each var + target environments 2. Update `${paths.references_dir}/env-vars.md` Change Log |
|
|
2186
|
-
| **Feature-flag / remote config** | New flag keys in code, new `remoteConfig` calls, growthbook/launchdarkly keys | Add keys in the project's flag system (Firebase Remote Config / Growthbook / LaunchDarkly / Unleash) |
|
|
2187
|
-
| **Auth provider configuration** | New auth provider initialization or scope change | Configure in the auth provider console matching `stack.auth_provider` (Firebase Console / Supabase dashboard / Clerk dashboard / Auth0 / Cognito) |
|
|
2188
|
-
| **Scheduled functions / cron** | New or modified cron/scheduled jobs | firebase: `firebase deploy --only functions`; vercel: deploy includes cron from `vercel.json`; aws: deploy EventBridge rule + Lambda |
|
|
2189
|
-
| **Database migrations** | New {entities}, field renames, data backfills referenced in code or ADRs | Run the project's migration command — varies by stack (firebase admin script / `supabase db push` / `prisma migrate deploy` / Mongo migration tool / SQL migrator) |
|
|
2190
|
-
| **New API endpoints** | New route files (`src/app/api/` Next.js, `app/routes/api.*` Remix, `src/routes/api/+server.ts` SvelteKit, etc.) | Verify CORS/auth config; update API docs if public |
|
|
2191
|
-
| **Third-party services** | New API keys, webhook URLs, or external service integrations | Configure in provider dashboard + add secrets to the deployment platform |
|
|
2192
|
-
| **DNS / domain changes** | Hosting or redirect config changes | Update DNS records on registrar; update domain settings on the deployment platform |
|
|
2193
|
-
| **Package upgrades with breaking changes** | Major version bumps in `package.json` / `pyproject.toml` / `Gemfile` | Verify compatibility; check migration guides |
|
|
2194
|
-
|
|
2195
|
-
### Output format
|
|
2196
|
-
|
|
2197
|
-
Present the checklist as a clearly formatted section in the final report.
|
|
2198
|
-
The example below assumes `stack.deployment: firebase` + `stack.database: firestore`;
|
|
2199
|
-
adapt commands and tags to the project's resolved stack.
|
|
2200
|
-
|
|
2201
|
-
```
|
|
2202
|
-
## Production Readiness Checklist
|
|
2203
|
-
|
|
2204
|
-
### Required before deploy
|
|
2205
|
-
1. **[DB Indexes — firestore]** Deploy composite indexes
|
|
2206
|
-
- Command: `firebase deploy --only firestore:indexes`
|
|
2207
|
-
- Reason: New compound query on `<entity>` (`<field1>` + `<field2>` + `<field3>`)
|
|
2208
|
-
|
|
2209
|
-
2. **[Environment Variable]** Add `<VAR_NAME>` to the deployment platform
|
|
2210
|
-
- Go to: <Vercel/Firebase/Cloudflare/AWS> > Project Settings > Environment Variables
|
|
2211
|
-
- Required for: Production, Preview
|
|
2212
|
-
- Value: (obtain from <provider> dashboard)
|
|
2213
|
-
|
|
2214
|
-
3. **[DB Access Rules — firestore]** Deploy updated security rules
|
|
2215
|
-
- Command: `firebase deploy --only firestore:rules`
|
|
2216
|
-
- Reason: New {entity} `<name>` access rules added
|
|
2217
|
-
|
|
2218
|
-
# Equivalent commands for other stacks:
|
|
2219
|
-
# stack.database: supabase → `supabase db push` (RLS migration)
|
|
2220
|
-
# stack.database: postgres → `prisma migrate deploy` (or project migration tool)
|
|
2221
|
-
# stack.database: mongodb → run the index/validator bootstrap script
|
|
2222
|
-
# stack.database: dynamodb → `cdk deploy` / `terraform apply` for the table+GSI
|
|
2223
|
-
|
|
2224
|
-
### No action needed
|
|
2225
|
-
- No new scheduled functions
|
|
2226
|
-
- No database migrations
|
|
2227
|
-
- No DNS changes
|
|
2228
|
-
|
|
2229
|
-
### Notes
|
|
2230
|
-
- DB index propagation can take time (firestore 5-10 min, postgres CONCURRENTLY minutes-to-hours on large tables, dynamodb GSI minutes); deploy BEFORE releasing the code
|
|
2231
|
-
- Environment variables must be set on the deployment platform BEFORE the deploy triggers
|
|
2232
|
-
```
|
|
2233
|
-
|
|
2234
|
-
### Auto-execution of agent-doable tasks
|
|
2235
|
-
|
|
2236
|
-
Before presenting the checklist, **auto-execute** all items that can be performed by the agent
|
|
2237
|
-
without manual intervention. Do NOT ask the user for approval — just run them.
|
|
2238
|
-
|
|
2239
|
-
**Auto-executable items** (run via Bash tool, no confirmation needed). Pick the
|
|
2240
|
-
command matching `stack.deployment` + `stack.database`. If the inferred command
|
|
2241
|
-
is wrong for the project, ask the user — never auto-execute a guess.
|
|
2242
|
-
|
|
2243
|
-
| Category | Command per `stack.deployment` | Auto-execute? |
|
|
2244
|
-
|----------|-------------------------------|--------------|
|
|
2245
|
-
| Database indexes | firebase → `firebase deploy --only firestore:indexes --project <id>`; supabase → `supabase db push`; vercel+postgres → `prisma migrate deploy` (or project-specific) | YES (when stack-matched) |
|
|
2246
|
-
| Persistence access rules | firebase → `firebase deploy --only firestore:rules --project <id>`; supabase → `supabase db push` (RLS migration); aws → CDK / Terraform apply | YES (when stack-matched) |
|
|
2247
|
-
| Storage access rules | firebase → `firebase deploy --only storage:rules --project <id>`; aws → S3 bucket policy apply via IaC | YES (when stack-matched) |
|
|
2248
|
-
| Scheduled functions | firebase → `firebase deploy --only functions --project <id>`; vercel → deploy step already includes cron from `vercel.json`; aws → CDK / Terraform apply | YES (when stack-matched) |
|
|
2249
|
-
|
|
2250
|
-
**Manual-only items** (report to user, do NOT auto-execute):
|
|
2251
|
-
|
|
2252
|
-
| Category | Why manual |
|
|
2253
|
-
|----------|-----------|
|
|
2254
|
-
| Environment variables | Requires deployment-platform dashboard access or secret values |
|
|
2255
|
-
| Feature-flag / remote config | Requires flag-system console (Firebase Remote Config / GrowthBook / LaunchDarkly / Unleash) |
|
|
2256
|
-
| Auth provider configuration | Requires console UI of the provider matching `stack.auth_provider` |
|
|
2257
|
-
| Database migrations / backfills | Risk of data loss — needs human judgment |
|
|
2258
|
-
| Third-party service config | Requires external dashboards and secrets |
|
|
2259
|
-
| DNS / domain changes | Risk of downtime — needs human judgment |
|
|
2260
|
-
|
|
2261
|
-
**Auto-execution procedure:**
|
|
2262
|
-
|
|
2263
|
-
1. For each auto-executable item detected, run the command immediately.
|
|
2264
|
-
2. Log the result (success/failure) in the tracker under `## Production Readiness`.
|
|
2265
|
-
3. In the final checklist output, mark auto-executed items with their result:
|
|
2266
|
-
```
|
|
2267
|
-
1. **[DB Indexes — <stack.database>]** Deploy indexes
|
|
2268
|
-
- Command: <stack-matched command from the Auto-executable table>
|
|
2269
|
-
- Result: DEPLOYED (took 45s) | FAILED (error: ...)
|
|
2270
|
-
```
|
|
2271
|
-
4. If an auto-execution FAILS: log the error, mark it as `MANUAL FALLBACK NEEDED`,
|
|
2272
|
-
and include it in the "Required before deploy" section for the user to handle.
|
|
2273
|
-
|
|
2274
|
-
### DB Index Verification (MUST — after deploy)
|
|
2275
|
-
|
|
2276
|
-
After the deploy command succeeds, verify the indexes are actually live before
|
|
2277
|
-
reporting success. The deploy command typically returns before index propagation
|
|
2278
|
-
completes (Firestore: 5–10 minutes; Postgres `CREATE INDEX CONCURRENTLY` on a
|
|
2279
|
-
large table: minutes to hours; DynamoDB GSI: minutes; Mongo background index:
|
|
2280
|
-
minutes to hours).
|
|
2281
|
-
|
|
2282
|
-
**Skip this section entirely when:**
|
|
2283
|
-
- the card has no `db_indexes` / `firestore_indexes` block, OR
|
|
2284
|
-
- `stack.database` is unset / `none`, OR
|
|
2285
|
-
- the card's index artifact is a SQL migration on a small table (the migration
|
|
2286
|
-
itself is synchronous and self-verifying — the deploy step already failed if
|
|
2287
|
-
the index didn't build).
|
|
2288
|
-
|
|
2289
|
-
**Verification procedure — pick the variant matching `stack.database`:**
|
|
2290
|
-
|
|
2291
|
-
#### Variant — Firestore (`stack.database: firestore`)
|
|
2292
|
-
|
|
2293
|
-
After `firebase deploy --only firestore:indexes` succeeds:
|
|
2294
|
-
|
|
2295
|
-
1. **Extract expected collection groups** from the local `firestore.indexes.json`:
|
|
2296
|
-
```bash
|
|
2297
|
-
cat firestore.indexes.json | python3 -c "
|
|
2298
|
-
import sys, json
|
|
2299
|
-
data = json.load(sys.stdin)
|
|
2300
|
-
groups = sorted(set(i['collectionGroup'] for i in data.get('indexes', [])))
|
|
2301
|
-
print('\n'.join(groups))
|
|
2302
|
-
"
|
|
2303
|
-
```
|
|
2304
|
-
|
|
2305
|
-
2. **Check index states** via Firestore REST API for each collection group:
|
|
2306
|
-
```bash
|
|
2307
|
-
TOKEN=$(gcloud auth print-access-token) && \
|
|
2308
|
-
for CG in <collection_groups>; do
|
|
2309
|
-
curl -s "https://firestore.googleapis.com/v1/projects/<your-firebase-project>/databases/(default)/collectionGroups/$CG/indexes" \
|
|
2310
|
-
-H "Authorization: Bearer $TOKEN" 2>/dev/null
|
|
2311
|
-
done | python3 -c "
|
|
2312
|
-
import sys, json, re
|
|
2313
|
-
raw = sys.stdin.read()
|
|
2314
|
-
creating = []
|
|
2315
|
-
for match in re.finditer(r'\{[^{}]*\"indexes\"[^}]*\}', raw, re.DOTALL):
|
|
2316
|
-
try:
|
|
2317
|
-
data = json.loads(match.group())
|
|
2318
|
-
for idx in data.get('indexes', []):
|
|
2319
|
-
state = idx.get('state', 'UNKNOWN')
|
|
2320
|
-
if state != 'READY':
|
|
2321
|
-
fields = ' + '.join(f.get('fieldPath','?') for f in idx.get('fields',[]))
|
|
2322
|
-
cg = idx.get('name','').split('/collectionGroups/')[1].split('/')[0] if '/collectionGroups/' in idx.get('name','') else '?'
|
|
2323
|
-
creating.append(f'{state}: {cg} ({fields})')
|
|
2324
|
-
except: pass
|
|
2325
|
-
if creating:
|
|
2326
|
-
print(f'NOT_READY ({len(creating)} indexes still building):')
|
|
2327
|
-
for c in creating: print(f' - {c}')
|
|
2328
|
-
else:
|
|
2329
|
-
print('ALL_READY')
|
|
2330
|
-
"
|
|
2331
|
-
```
|
|
2332
|
-
|
|
2333
|
-
3. **Poll if NOT_READY** — re-check every 30 seconds, up to 10 retries (5 minutes max).
|
|
2334
|
-
|
|
2335
|
-
4. **Final status**:
|
|
2336
|
-
- All `READY` → `VERIFIED READY`.
|
|
2337
|
-
- Still `CREATING` after 10 retries → `DEPLOYED BUT BUILDING` (warning).
|
|
2338
|
-
- Any `NEEDS_REPAIR` / `ERROR` → `INDEX ERROR — manual intervention required`.
|
|
2339
|
-
|
|
2340
|
-
#### Variant — Postgres / Supabase (`stack.database` ∈ {postgres, supabase})
|
|
2341
|
-
|
|
2342
|
-
After the migration / `supabase db push` succeeds:
|
|
2343
|
-
|
|
2344
|
-
```bash
|
|
2345
|
-
# For each index named in the migration:
|
|
2346
|
-
psql "$DATABASE_URL" -c "SELECT indexname, indexdef FROM pg_indexes WHERE indexname = '<index_name>';"
|
|
2347
|
-
# If the migration used CREATE INDEX CONCURRENTLY on a large table, also check:
|
|
2348
|
-
psql "$DATABASE_URL" -c "SELECT pid, phase, blocks_total, blocks_done FROM pg_stat_progress_create_index;"
|
|
2349
|
-
```
|
|
2350
|
-
|
|
2351
|
-
If `pg_stat_progress_create_index` returns rows → index still building, poll every
|
|
2352
|
-
30s. If `pg_indexes` returns 0 rows for an expected name → CRITICAL (migration
|
|
2353
|
-
silently skipped or rolled back).
|
|
2354
|
-
|
|
2355
|
-
#### Variant — MongoDB (`stack.database: mongodb`)
|
|
2356
|
-
|
|
2357
|
-
After the bootstrap script / migration runs:
|
|
2358
|
-
|
|
2359
|
-
```bash
|
|
2360
|
-
mongosh "$MONGO_URL" --eval "db.<entity>.getIndexes()"
|
|
2361
|
-
```
|
|
2362
|
-
|
|
2363
|
-
Confirm every expected `name`/`key` is present. For background-built indexes, watch
|
|
2364
|
-
`db.currentOp({'$or':[{op:'command','command.createIndexes':{$exists:true}}]})` until empty.
|
|
2365
|
-
|
|
2366
|
-
#### Variant — DynamoDB (`stack.database: dynamodb`)
|
|
2367
|
-
|
|
2368
|
-
After `cdk deploy` / `terraform apply`:
|
|
2369
|
-
|
|
2370
|
-
```bash
|
|
2371
|
-
aws dynamodb describe-table --table-name <table> \
|
|
2372
|
-
--query 'Table.GlobalSecondaryIndexes[].{Name:IndexName,Status:IndexStatus}'
|
|
2373
|
-
```
|
|
2374
|
-
|
|
2375
|
-
All GSIs must show `ACTIVE`. `CREATING` → poll; `DELETING` / `UPDATING` → manual review.
|
|
2376
|
-
|
|
2377
|
-
**Checklist output format with verification:**
|
|
2378
|
-
```
|
|
2379
|
-
1. **[DB Indexes — <stack.database>]** Deploy indexes
|
|
2380
|
-
- Command: <stack-matched command>
|
|
2381
|
-
- Deploy: SUCCESS (took 45s)
|
|
2382
|
-
- Verification: ALL READY (5/5) | BUILDING (2 still creating after 5min) | ERROR (details)
|
|
2383
|
-
```
|
|
2384
|
-
|
|
2385
|
-
### Rules
|
|
2386
|
-
|
|
2387
|
-
- **Always present this section**, even if the checklist is empty (in that case, state "No infrastructure changes required — deploy is code-only").
|
|
2388
|
-
- Order items by **deployment sequence** (items that must happen first go first — e.g., indexes before code deploy, env vars before code deploy).
|
|
2389
|
-
- For each item, include the **reason** (which card/feature requires it) and the **exact command or UI path**.
|
|
2390
|
-
- If an item is **uncertain** (e.g., you suspect a new index might be needed but aren't sure), mark it with `VERIFY` and explain what to check.
|
|
2391
|
-
- **Update the tracker** with the full checklist under a new `## Production Readiness` section.
|
|
2392
|
-
|
|
2393
|
-
---
|
|
2394
|
-
|
|
2395
|
-
## Context recovery protocol
|
|
2396
|
-
|
|
2397
|
-
If at ANY point you are unsure where you are in the batch:
|
|
2398
|
-
1. Read your tracker file (`/tmp/batch-tracker-<FIRST-CARD-ID>.md`)
|
|
2399
|
-
2. Check `## Current Card` — if populated, resume that card at the listed phase.
|
|
2400
|
-
3. Check `## Card Queue` — find the next unchecked card.
|
|
2401
|
-
4. Check `## Completed Cards` — know what's already done (don't redo).
|
|
2402
|
-
5. Continue the pipeline from where you left off.
|
|
2403
|
-
|
|
2404
|
-
---
|
|
2405
|
-
|
|
2406
|
-
## Parallelism rules
|
|
2407
|
-
|
|
2408
|
-
### Sequential mode (default for small batches)
|
|
2409
|
-
|
|
2410
|
-
- Cards execute one at a time through the full per-card pipeline (Phases 1-5).
|
|
2411
|
-
- Code review and doc review for the same card run as **parallel read-only audits**, then fixes are applied by domain owner: **doc findings → `doc-reviewer` (write mode)**, code/security/migration findings → `coder`. (Sequential Phase 3 is even simpler — doc-reviewer runs alone, so it audits AND applies in one invocation.)
|
|
2412
|
-
- This mode is unchanged from the original behavior.
|
|
2413
|
-
|
|
2414
|
-
### Team mode (for complex batches)
|
|
2415
|
-
|
|
2416
|
-
- Cards within the same `execution_strategy.groups` level (same `level`) run in parallel via isolated coder agents.
|
|
2417
|
-
- Groups execute sequentially (group 0 → group 1 → group 2...).
|
|
2418
|
-
- Review + QA run ONCE per group (combined), not per card.
|
|
2419
|
-
- The orchestrator holds ONLY coordination state, never implementation details.
|
|
2420
|
-
- File ownership map is enforced per-agent via MAY EDIT / FORBIDDEN lists.
|
|
2421
|
-
- See "Team Mode" section below for full workflow.
|
|
2422
|
-
|
|
2423
|
-
### Common rules (both modes)
|
|
2424
|
-
|
|
2425
|
-
- The file-ownership map is the authoritative source for which files each agent may edit.
|
|
2426
|
-
- When running parallel agents, expect "file modified since read" errors on shared files (like the backlog yml) — handle gracefully.
|
|
2427
|
-
- When running in parallel, each parallel branch updates the tracker with its own card — use card ID as prefix to avoid conflicts.
|
|
2428
|
-
|
|
2429
|
-
---
|
|
2430
|
-
|
|
2431
|
-
## Team Mode (parallel coder agents with isolated contexts)
|
|
2432
|
-
|
|
2433
|
-
When the complexity assessment (step 3c) selects team mode, the orchestrator changes role: instead of executing each card's pipeline sequentially, it coordinates parallel coder agents — each with its OWN isolated context window.
|
|
2434
|
-
|
|
2435
|
-
**Key principle**: the orchestrator stays LEAN. It holds only:
|
|
2436
|
-
- The tracker file path
|
|
2437
|
-
- Parallel group status (pending/active/done)
|
|
2438
|
-
- Completion verdicts per card (pass/fail + files changed)
|
|
2439
|
-
|
|
2440
|
-
It does NOT accumulate implementation details, codebase-architect findings, or review outputs — those live and die in each agent's isolated context.
|
|
2441
|
-
|
|
2442
|
-
### Team Mode Pre-flight
|
|
2443
|
-
|
|
2444
|
-
After the standard pre-flight (steps 1-7), add:
|
|
2445
|
-
|
|
2446
|
-
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.
|
|
2447
|
-
2. Update tracker with team mode section:
|
|
2448
|
-
```
|
|
2449
|
-
## Team Mode
|
|
2450
|
-
Status: active
|
|
2451
|
-
|
|
2452
|
-
## Parallel Groups
|
|
2453
|
-
| Group | Cards | Status |
|
|
2454
|
-
|-------|-------|--------|
|
|
2455
|
-
| 0 | FEAT-01 | pending |
|
|
2456
|
-
| 1 | FEAT-02, FEAT-03 | pending |
|
|
2457
|
-
| 2 | FEAT-04, FEAT-05 | pending |
|
|
2458
|
-
```
|
|
2459
|
-
|
|
2460
|
-
### Per-Group Execution
|
|
2461
|
-
|
|
2462
|
-
Process groups in order (0, 1, 2, ...). Within each group, spawn coder agents IN PARALLEL — one per card.
|
|
2463
|
-
|
|
2464
|
-
#### Step A: Pre-compute shared context (ONCE per group)
|
|
2465
|
-
|
|
2466
|
-
Before spawning coders, the orchestrator runs **codebase-architect** ONCE for the entire group (not per card). This single call covers all cards in the group.
|
|
2467
|
-
|
|
2468
|
-
Prompt:
|
|
2469
|
-
```
|
|
2470
|
-
Explore the codebase for context relevant to these cards:
|
|
2471
|
-
[list card IDs + their scope.summary, one line each]
|
|
2472
|
-
|
|
2473
|
-
Focus on: [combined files_likely_touched from all cards in group]
|
|
2474
|
-
Return: file paths, type signatures, existing patterns. Max 30 lines.
|
|
2475
|
-
```
|
|
2476
|
-
|
|
2477
|
-
This is the ONLY context the orchestrator accumulates per group. After passing it to the coders, it can be purged.
|
|
2478
|
-
|
|
2479
|
-
**Persist for review reuse (since v3.35.0)** — also write these findings to
|
|
2480
|
-
`/tmp/arch-baseline-group-<FIRST-CARD-ID>.md`. D.4b's per-card `/codexreview` lean contract points
|
|
2481
|
-
its `arch_baseline_path` at this file, so the review reuses the group baseline instead of re-spawning
|
|
2482
|
-
`codebase-architect`.
|
|
2483
|
-
|
|
2484
|
-
#### Step B: Spawn parallel coder agents
|
|
2485
|
-
|
|
2486
|
-
**→ Visibility (wave change)**: this is a new wave starting. TaskUpdate ALL of this group's card spine tasks → `in_progress`, and emit a Progress Bar with the new `Wave <X>/<Y>` header per § "Progress Visibility".
|
|
2487
|
-
|
|
2488
|
-
For each card in the current group, spawn a coder agent using the Agent tool. ALL agents for the group MUST be spawned in a **SINGLE message** (multiple Agent tool calls) to run truly in parallel.
|
|
2489
|
-
|
|
2490
|
-
Each coder agent receives a **SELF-CONTAINED** mission briefing that includes EVERYTHING it needs — it will NOT call codebase-architect or plan-auditor itself:
|
|
2491
|
-
|
|
2492
|
-
```
|
|
2493
|
-
Agent tool call:
|
|
2494
|
-
subagent_type: "coder"
|
|
2495
|
-
mode: "bypassPermissions"
|
|
2496
|
-
run_in_background: true
|
|
2497
|
-
name: "coder-<CARD-ID>"
|
|
2498
|
-
prompt: |
|
|
2499
|
-
## AUTONOMOUS CARD IMPLEMENTATION — <CARD-ID>
|
|
2500
|
-
|
|
2501
|
-
You are implementing this card AUTONOMOUSLY. Complete ALL phases below
|
|
2502
|
-
without external coordination. You have your own isolated context.
|
|
2503
|
-
|
|
2504
|
-
### 1. Card Specification (verbatim)
|
|
2505
|
-
Requirements:
|
|
2506
|
-
[copy from card YAML]
|
|
2507
|
-
|
|
2508
|
-
Acceptance Criteria:
|
|
2509
|
-
[copy from card YAML]
|
|
2510
|
-
|
|
2511
|
-
### 2. Codebase Context (pre-computed)
|
|
2512
|
-
[paste codebase-architect findings from Step A]
|
|
2513
|
-
|
|
2514
|
-
### 3. Working Directory
|
|
2515
|
-
All work MUST happen in the worktree: <worktree-path>
|
|
2516
|
-
cd to this directory before any file operations.
|
|
2517
|
-
|
|
2518
|
-
### 4. File Permissions (ENFORCED)
|
|
2519
|
-
MAY EDIT:
|
|
2520
|
-
[files from ownership map for THIS card only]
|
|
2521
|
-
|
|
2522
|
-
FORBIDDEN:
|
|
2523
|
-
- ALL files not in the MAY EDIT list
|
|
2524
|
-
- Do NOT create files outside the designated paths
|
|
2525
|
-
|
|
2526
|
-
### 5. Design Reference (if UI card)
|
|
2527
|
-
[path to design.html if exists]
|
|
2528
|
-
|
|
2529
|
-
### 6. Your Pipeline
|
|
2530
|
-
Execute these steps in order:
|
|
2531
|
-
a) Print the numbered requirements checklist (anti-skip measure)
|
|
2532
|
-
b) Implement ALL requirements
|
|
2533
|
-
c) Run: npx tsc --noEmit && npx eslint --max-warnings=0 <your-files>
|
|
2534
|
-
d) Self-heal up to 3 times if checks fail
|
|
2535
|
-
e) Verify completeness: for each requirement, confirm code exists (read it)
|
|
2536
|
-
f) If any requirement is missing after implementation, implement it now
|
|
2537
|
-
g) Output the completion report (MANDATORY format below)
|
|
2538
|
-
|
|
2539
|
-
### 7. Completion Report (MANDATORY)
|
|
2540
|
-
```completion-report
|
|
2541
|
-
card: <CARD-ID>
|
|
2542
|
-
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)
|
|
2543
|
-
requirements:
|
|
2544
|
-
- id: 1
|
|
2545
|
-
text: "[text]"
|
|
2546
|
-
status: done | not_implemented # per-requirement is BINARY (legacy row-level partial/blocked were silent-deferral channels — removed)
|
|
2547
|
-
evidence: "file:line"
|
|
2548
|
-
files_changed:
|
|
2549
|
-
- path/to/file.ts
|
|
2550
|
-
build_status: pass | fail
|
|
2551
|
-
lint_status: pass | fail
|
|
2552
|
-
tsc_status: pass | fail | n/a # n/a when stack.language excludes typescript
|
|
2553
|
-
retry_count: N
|
|
2554
|
-
```
|
|
2555
|
-
```
|
|
2556
|
-
|
|
2557
|
-
#### Step C: Wait for group completion
|
|
2558
|
-
|
|
2559
|
-
The orchestrator waits for ALL background agents in the group to complete. It will be notified automatically as each finishes (`run_in_background`).
|
|
2560
|
-
|
|
2561
|
-
> **Do NOT poll with `sleep N; echo "waiting..."` loops.** Background agents (and background `Bash` commands) re-invoke the orchestrator automatically when they finish — issuing `sleep`/`echo` "waiting" turns burns orchestrator turns and tokens for zero progress. Simply end your turn after spawning the background work; you will be woken on completion. This applies to EVERY barrier in Step D (D.1 build, D.2 reviewers, D.3/D.3b agents, D.4 qa-sentinel, D.4a doc-reviewer, D.4b `/codexreview`), not just Step C.
|
|
2562
|
-
|
|
2563
|
-
For each completed agent:
|
|
2564
|
-
1. Read the completion report from the agent's output.
|
|
2565
|
-
2. Log to tracker: card ID, status, files changed, build/lint status.
|
|
2566
|
-
3. Do NOT read or store implementation details — only the verdict.
|
|
2567
|
-
|
|
2568
|
-
**If an agent fails** (status: failed after 3 retries — the central repair cap):
|
|
2569
|
-
- Log failure in tracker `## Issues & Flags`.
|
|
2570
|
-
- Other agents in the group continue unaffected.
|
|
2571
|
-
- After group completes, ask user: retry failed card or skip?
|
|
2572
|
-
- **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.
|
|
2573
|
-
|
|
2574
|
-
#### Step D: Post-group review + QA (ALL sub-steps MANDATORY)
|
|
2575
|
-
|
|
2576
|
-
> **The sub-steps below are ALL MANDATORY.** The previous lean Step D (build → combined review → qa → codex → commit) was an incident-causing shortcut (FEAT-0006: 10 sub-cards committed with 0 invocations of Phase 2.5b / 2.55 / 2.6 / 3 / 3.5 / 3.7) and is now FORBIDDEN. Every card in the group MUST complete every per-card sub-step (D.3a, D.3b, D.3c, D.4a) before the group reaches D.5 commit. Skipping any sub-step "to save time", "to save tokens", "because the diff is small", or for any model-invented reason is a protocol violation. Auto Mode does NOT override this.
|
|
2577
|
-
|
|
2578
|
-
After ALL agents in the group complete successfully:
|
|
2579
|
-
|
|
2580
|
-
1. **D.1 — Build verification (group)** — Run `npm run build` in the worktree to verify combined changes compile (redirect to `/tmp/build-group.txt` per § "Context economy"; surface only exit code + bounded extract on failure). If build fails, identify which card's changes broke it (from `git diff --name-only` per card), spawn a targeted fix-coder for those files only.
|
|
2581
|
-
|
|
2582
|
-
1.5. **D.1.5 — Effective per-card review profile (compute ONCE; drives D.2 + D.4b)** — For EACH card in the group, compute its **effective codex profile** with the SAME deterministic rule the sequential Phase 3.7 Step C uses, so the two paths never disagree:
|
|
2583
|
-
- **Floor**: read the card's `review_profile` field (`skip`/`light`/`balanced`/`deep`) per the QA Profile Selector (fallback-computed only for legacy cards lacking the field).
|
|
2584
|
-
- **Escalation-only (Step A detector)**: run the Phase 3.7 **Step A** high-risk detector (bash + grep) on THIS card's committed diff (`git diff "$TRUNK...HEAD" -- <card files from ownership map>`). A matched trigger promotes `light`→`full`; it can NEVER downgrade `full`→`light`. The card's `review_profile` is the floor; the detector is the safety net on top.
|
|
2585
|
-
- **Partition** the group into two lists and log them in the tracker under `## Team Mode`:
|
|
2586
|
-
- `LIGHT_CARDS` = cards whose effective profile is `light` or `skip` **AND** zero Step-A triggers.
|
|
2587
|
-
- `FULL_CARDS` = all others (effective profile `balanced`/`deep`, OR any Step-A trigger).
|
|
2588
|
-
- **Sub-classify `TRIVIAL_CARDS` ⊆ `LIGHT_CARDS`** = cards that are `IS_TRIVIAL` on the committed diff (§ "Trivial-card fast-lane": `review_profile == skip` AND 0 Step-A triggers AND **non-source diff**). These are the LIGHT cards that have nothing for `code-reviewer` to review. (A `skip` card whose diff DID touch a source file is in `LIGHT_CARDS` but NOT `TRIVIAL_CARDS` — the guard keeps it on the code-review path.)
|
|
2589
|
-
- **Sub-classify `DOC_DEFER_CARDS`** (since v4.7.0, for #2 doc deferral) = cards with `review_profile == light` whose committed diff touches **NO documentation file** (no `.md`, no path under `${paths.references_dir}`, no data-model/ssot/api doc). Their per-card doc-review is deferred to the Final F.3 doc-reviewer. (Trivial cards, and any card whose diff touches a doc file, are NOT in this set — doc-review stays relevant for them.)
|
|
2590
|
-
- Log: `## D.1.5 Effective Profiles\n<CARD-ID>: profile=<floor> triggers=<n> diff=<source|non-source> → effective=<light|full> (<LIGHT_CARDS|FULL_CARDS>)<, TRIVIAL / DOC_DEFER if applicable>` per card. This single computation is the SSOT for D.2 (code-reviewer + doc-reviewer scoping), D.3b/D.3c (already skipped for trivial), and D.4b (inclusion) — do NOT recompute it downstream.
|
|
2591
|
-
|
|
2592
|
-
2. **D.2 — Combined static review (group)** — Two reviewers, **scoped by the D.1.5 partition** so each card gets exactly ONE per-card/group code review proportional to its risk (the other is the Final FULL gate):
|
|
2593
|
-
- **doc-reviewer — over the group MINUS `DOC_DEFER_CARDS`** (since v4.7.0). It runs **read-only here** (it cannot write while code-reviewer reads in parallel — parallel-safety), MUST **attribute every doc finding to a specific card** (by file → ownership map), and applies the full Phase 3 mandate INCLUDING the spec/docs-drift→bug lens (since v3.35.0). The `DOC_DEFER_CARDS` (light, no-doc diff per D.1.5) are excluded — their doc-review is deferred to the Final F.3 doc-reviewer (batch-wide). **If the group is entirely `DOC_DEFER_CARDS` → skip the D.2 doc-reviewer** and log `D.2 doc-reviewer: DEFERRED to Final FULL gate (all cards light + no-doc diff)`. D.4a consumes the per-card findings (for the non-deferred cards) and dispatches the doc-reviewer (now alone, in write mode) to apply them — no second AUDIT spawn, but the FIXES are still owned by doc-reviewer.
|
|
2594
|
-
- **code-reviewer — scoped to the diff-union of `LIGHT_CARDS` MINUS `TRIVIAL_CARDS`** (run it in parallel with the doc-reviewer over those files). These light non-trivial cards skip D.4b, so D.2 is their single per-card code review (the cross-batch Codex pass at Final covers them adversarially). **`TRIVIAL_CARDS` are excluded from the code-reviewer scope** — their diff is non-source, so there is nothing to code-review (doc-reviewer still covers them via the whole-group pass above; the Final FULL gate covers them adversarially). **If `LIGHT_CARDS \ TRIVIAL_CARDS` is empty → do NOT spawn code-reviewer at D.2** (every remaining card is either `FULL_CARDS` — deeper review at D.4b — or `TRIVIAL_CARDS` — nothing to review). Log the deterministic gate reason: `D.2 code-reviewer: scope=[<ids>] | excluded-trivial=[<ids>] | SKIPPED (no code-bearing light cards)`.
|
|
2595
|
-
- **Tradeoff (documented, accepted — see top-of-file `REVIEW DEPTH SCALES` clause)**: for `FULL_CARDS`, cross-card detection moves from the per-group D.2 pass to the per-batch **Final-review FULL gate** (Codex over the entire batch diff, plus code-reviewer fallback) — same merge-gate safety, feedback arrives at batch-end rather than per-group. This is the intended de-duplication: `FULL_CARDS` are NOT re-reviewed by a group-level code-reviewer on top of their D.4b `/codexreview`.
|
|
2596
|
-
|
|
2597
|
-
3. **D.3 — Apply fixes (group)** — If D.2 findings exist, spawn ONE fix-coder to apply all fixes in a single pass. Run build + lint after.
|
|
2598
|
-
|
|
2599
|
-
3a. **D.3a — Phase 2.5b AC-Closure Gate (per-card, BLOCKING — non-skippable)** — For EACH card in the group, **sequentially**, invoke the full Phase 2.5b gate as documented in `### Phase 2.5b — AC-Closure Gate (BLOCKING — Scope Closure Discipline)`. This includes: build the AC Closure Ledger from the card YAML, run the rationalization scan, invoke `AskUserQuestion` one-per-deferred-AC, run the `implementation_notes` deferral audit, and persist the ledger in the tracker. Until EVERY card in the group exits PASS, do NOT proceed to D.3b. Cards exiting with `not_implemented` ACs that the user routes to "Implementa adesso" must finish their fix-coder loop and re-pass the gate before D.3b starts for the next card. Log under `## AC Closure Ledger — <CARD-ID>` per card.
|
|
2600
|
-
|
|
2601
|
-
3b. **D.3b — Phase 2.55 Simplify (per-card, FANNED OUT across the group)** — The Simplify agents are **read-only analysis on file-disjoint per-card diffs** (the orchestrator applies the fixes afterward), so there is NO reason to run them one card at a time. **Spawn the per-card Simplify analysis for ALL eligible cards in PARALLEL** — in a SINGLE message, fire each card's Phase 2.55 trio (Reuse / Quality / Efficiency) against that card's diff captured to `/tmp/diff-<CARD-ID>.txt` (per Phase 2.55 step 2 — pass each trio the **path**, scoped to the card's File Ownership Map; never inline the diff). Per-card (not group-aggregate) so findings stay attributable. When all analyses return, **apply fixes per card** (file-disjoint → no write conflict), then re-run `npm run lint` and `npx tsc --noEmit` on the worktree ONCE for the whole group (redirect to disk per § "Context economy"). (Concurrency is capped by the platform; passing N cards is safe — excess agents queue.)
|
|
2602
|
-
- **Gate (enumerated, `review_profile`-driven)**: SKIP D.3b for a card whose `review_profile == skip` (trivial / non-implementable card — Simplify is quality-only, so there is no merge-gate coverage to lose, and there is no substantive diff to simplify). Log `simplify: SKIPPED (review_profile=skip)`. For `light`/`balanced`/`deep` cards D.3b runs unchanged. This is the ONLY enumerated skip — never skip D.3b "for time" on a `light`+ card. (Skipped cards are simply omitted from the parallel fan-out.)
|
|
2603
|
-
|
|
2604
|
-
3c. **D.3c — Phase 2.6 E2E-Review (per-card)** — First, evaluate the existing Gate table for EVERY card at once (skip when `features.has_e2e_review: false`, backend-only diff per the diff predicate documented in Phase 2.6, or card type in the Phase 2.6 skip set — `backend`/`api`/`db`/`infra`/`docs`/`chore`/`config`). In practice most cards in a group skip this gate (backend/db/api), so the eligible set is usually 0–1. For the cards that PASS the gate, invoke `/e2e-review` in programmatic mode with that card's payload. Each `/e2e-review` keeps its own isolated state dir (`.baldart/e2e-review/<CARD-ID>/`), so multiple runs do not clobber each other's artifacts.
|
|
2605
|
-
- **Parallel-when-safe**: if **two or more** cards pass the gate, you MAY fan them out in parallel ONLY when they hit **disjoint routes/pages** — the genuinely shared resource is the worktree's single dev-server port, and concurrent Playwright sessions against one server are fine for disjoint routes. If the eligible cards touch overlapping routes (or `/e2e-review` spins its own server and a port clash is possible), run those **sequentially** to avoid a flaky cross-test. Default to parallel for the common disjoint case; fall back to sequential on any contention.
|
|
2606
|
-
- 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.
|
|
2607
|
-
|
|
2608
|
-
4. **D.4 — QA gate (group; since v4.7.0 — runs only for `deep` / risk-escalation, else deferred to Final)** — Read each card's `review_profile` field and the D.1.5 Step-A trigger result. **Run the group qa-sentinel (once, at FULL) iff** the group's MAX profile is `deep` **OR** any card in the group had a Step-A risk escalation. **Otherwise (max profile ≤ `balanced`, no escalation) → DEFER the group QA to the Final Review F.3 qa-sentinel** (FULL suite + build + audit over the entire batch — the unconditional merge gate); log `D.4 QA: DEFERRED to Final FULL gate (group max=balanced, no risk escalation)`. This mirrors sequential step 21b. When it DOES run, invoke qa-sentinel at FULL (the combined group diff must be validated together) using the same prompt contract as Phase 3.5 step 22. ⚠️ A balanced-only group runs its first suite at the Final gate; merge safety is preserved because Final is FULL over the whole batch.
|
|
2609
|
-
|
|
2610
|
-
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.
|
|
2611
|
-
|
|
2612
|
-
4b. **D.4b — Pre-Merge Codex Review Gate (per-card, profile-gated via D.1.5)** — Invoke `/codexreview` for **EACH card in `FULL_CARDS`** (the partition computed at D.1.5), one at a time, BEFORE any commit. This mirrors Phase 3.7 of the sequential path.
|
|
2613
|
-
- **`LIGHT_CARDS` → SKIP D.4b** (enumerated `review_profile`-driven gate reason, NOT a time skip). A `light`/`skip` 0-trigger card already received its single per-card code review at the **D.2 group pass**, and its Codex-adversarial review is **guaranteed by the unconditional Final-review FULL gate** (Codex over the entire batch diff, post-batch). Running `/codexreview` here at `light` would only re-run `code-reviewer` + FP-gate (Codex is dropped at `light` since v3.38.0) — a pure duplicate of D.2. Log per card: `codex-review: SKIPPED (light, 0 triggers — D.2 group code-review covered + Codex adversarial guaranteed by Final FULL gate)`.
|
|
2614
|
-
- **`FULL_CARDS` → run `/codexreview` as today** (the per-card Codex adversarial + CoVe + FP-gate pass is exactly where the per-card code review for these cards lives — D.2 deliberately did NOT re-review them). The profile passed is always `full` (D.1.5 already resolved it; do NOT recompute). Keep the sequential one-at-a-time loop (avoid N concurrent `/codexreview`, each of which fans out multiple sub-agents → rate-limit risk).
|
|
2615
|
-
Apply the same fix sub-loop as sequential Phase 3.7 Step C.4: if the consolidated report shows verified BLOCKER/HIGH findings, spawn a fix-coder and — **re-writing the consumed-once lean contract first** — re-invoke `/codexreview` via the Skill tool with `args: <CARD-ID>` (max 2 retries per card; a bare prose mention or a missing card-ID would let the retry review the wrong card). If still BLOCKER/HIGH after retries, ask the user before proceeding to D.5. The D.5 commits MUST NOT happen until every card in the group has a PASS verdict (or explicit user override via `AskUserQuestion`). Log results in the tracker under `## Pre-Merge Codex Review` per card. **Lean + profile (since v3.35.0)**: before each card's `/codexreview`, apply the same Review Profile Selector and write the same `/tmp/codexreview-lean-<CARD-ID>.json` contract as sequential Phase 3.7 Step C — `arch_baseline_path` pointing at `/tmp/arch-baseline-group-<FIRST-CARD-ID>.md`, `skip_doc_reviewer: true`, `skip_api_perf_auditor: true` (since v4.7.0 — api-perf deferred to the Final F.3 batch-wide auditor), and `profile: full` (every card that reaches D.4b is in `FULL_CARDS` per D.1.5 — `light`/`skip` 0-trigger cards were already partitioned out and skip D.4b entirely; do NOT recompute the profile here). `full` runs the standard pipeline (Codex adversarial + CoVe + FP-gate, minus the duplicate doc-reviewer). The merge-gate safety for the skipped `LIGHT_CARDS` is the post-batch **Final-review FULL gate** (a single FULL `/codexreview` over the entire batch diff, which team mode reaches via "Post-batch — same as sequential mode"). To make D.4b run for every card again (pre-v4.5.0 behavior), drop the D.1.5 partition and iterate over all group cards here at their per-card profile; the final full gate stays regardless.
|
|
2616
|
-
|
|
2617
|
-
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):
|
|
2618
|
-
```bash
|
|
2619
|
-
cd <worktree-path>
|
|
2620
|
-
# For each card in the group:
|
|
2621
|
-
git add <card's-files-only>
|
|
2622
|
-
# Disambiguate "nothing to commit" from a hook rejection BEFORE committing:
|
|
2623
|
-
if [ -z "$(git status --porcelain)" ]; then
|
|
2624
|
-
echo "D.5 <CARD-ID>: nothing staged — already committed upstream; record HEAD and skip"
|
|
2625
|
-
else
|
|
2626
|
-
git commit -m "[CARD-ID] Brief description"
|
|
2627
|
-
fi
|
|
2628
|
-
```
|
|
2629
|
-
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.
|
|
2630
|
-
|
|
2631
|
-
6. **D.6 — Update backlog (MANDATORY — do NOT skip)** — For EACH card in the group:
|
|
2632
|
-
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).
|
|
2633
|
-
b. **Verify the write**: re-read the YAML file and confirm `status: DONE` is present. If not, retry.
|
|
2634
|
-
c. Stage the updated YAML and include it in the card's commit (or as an immediate follow-up commit).
|
|
2635
|
-
d. Log in tracker: `card_status: DONE (verified)` for each card.
|
|
2636
|
-
e. **→ Visibility**: TaskUpdate each card's spine task → `completed` (strip any live phase suffix) as it reaches DONE here.
|
|
2637
|
-
Note: Phase 6b (Status Reconciliation) will catch any card missed here, but aim for zero misses.
|
|
2638
|
-
|
|
2639
|
-
#### Step D coverage assertion (MANDATORY end-of-group check)
|
|
2640
|
-
|
|
2641
|
-
Before moving to Step E, the orchestrator MUST verify the tracker contains, for EACH card in the group, ALL of the following entries (or an explicit gate-skip log with the documented reason):
|
|
2642
|
-
|
|
2643
|
-
- `## AC Closure Ledger — <CARD-ID>` with `ac-closure: implemented=N | user-approved deferrals=M | follow-up cards created=K` (NEVER skipped — applies to trivial cards too)
|
|
2644
|
-
- `simplify: <N fixes | clean — 0 fixes | SKIPPED (review_profile=skip)>` (per-card from D.3b)
|
|
2645
|
-
- `e2e-review: <status>` (with documented gate-skip reason if SKIP)
|
|
2646
|
-
- `doc-review: <status | DEFERRED to Final FULL gate (DOC_DEFER_CARDS: light + no-doc diff)>` (from D.4a — runs for trivial cards too; the DEFERRED form is valid ONLY for `DOC_DEFER_CARDS` per D.1.5)
|
|
2647
|
-
- `qa: <profile=... | verdict=... | mechanical-only (trivial) | DEFERRED to Final FULL gate (group max=balanced, no risk escalation)>` (group-level from D.4; the DEFERRED form is valid when the group max profile ≤ balanced with no Step-A escalation)
|
|
2648
|
-
- `api-perf: <covered at D.4b | DEFERRED to Final FULL gate (skip_api_perf_auditor)>` (per-card — `skip_api_perf_auditor` defers it to F.3 batch-wide; DEFERRED is the normal v4.7.0 value)
|
|
2649
|
-
- `code-review: <covered at D.2 | covered at D.4b | SKIPPED (trivial — non-source diff)>` (per-card — the trivial SKIP is valid ONLY for `TRIVIAL_CARDS` per the D.1.5 partition)
|
|
2650
|
-
- `codex-review: <verdict | SKIPPED (light, 0 triggers — D.2 group code-review covered + Final FULL gate) | SKIPPED (trivial — non-source diff; covered by Final FULL gate)>` (per-card from D.4b — the SKIPPED forms are valid ONLY for `LIGHT_CARDS` / `TRIVIAL_CARDS` respectively)
|
|
2651
|
-
|
|
2652
|
-
A missing entry means a sub-step was skipped. An entry whose value is a **`review_profile`-driven SKIP/DEFER**, an **`IS_TRIVIAL` SKIP**, or a **`/prd`-provenance SKIP** with a documented enumerated reason above (D.3b `skip` profile; D.4b `LIGHT_CARDS`; code/codex `TRIVIAL_CARDS`; doc-review `DOC_DEFER_CARDS`; QA `group max=balanced, no escalation`; api-perf `skip_api_perf_auditor`; plan-auditor `holistic_audit provenance`) is a VALID, present entry — not a violation; all defer to the unconditional Final FULL gate. What remains forbidden: a missing entry, or a skip whose reason is `time budget` / `to save tokens` / any model-invented constraint. If any entry is genuinely missing, do NOT proceed to Step E — return to the missing sub-step and execute it. Documenting "skipped per time budget" or similar is a protocol violation per the top-of-file rigidity clause.
|
|
2653
|
-
|
|
2654
|
-
#### Step E: Context purge + next group
|
|
2655
|
-
|
|
2656
|
-
After committing all cards in the group:
|
|
2657
|
-
1. Update tracker: move group to done, log all results per card.
|
|
2658
|
-
2. **PURGE**: forget all implementation details, review findings, architect context.
|
|
2659
|
-
3. **→ Visibility**: emit a Progress Bar reflecting the wave boundary (this wave done; next `Wave <X+1>/<Y>` pending) per § "Progress Visibility".
|
|
2660
|
-
4. Move to the next pending group (Step A again).
|
|
2661
|
-
|
|
2662
|
-
### Sequential fallback within team mode
|
|
2663
|
-
|
|
2664
|
-
If two cards in the same parallel group are discovered at runtime to have a file conflict (e.g., one coder created an unexpected file that overlaps):
|
|
2665
|
-
1. Detect via file-diff gate after Step C.
|
|
2666
|
-
2. Revert the later card's conflicting files.
|
|
2667
|
-
3. Re-run that card as a standalone sequential step after the group.
|
|
2668
|
-
|
|
2669
|
-
### Dependency gates between groups
|
|
2670
|
-
|
|
2671
|
-
Before starting group N, verify ALL cards in groups 0..N-1 are status: done. If any card in a previous group failed and was skipped:
|
|
2672
|
-
- If cards in group N `depends_on` it: skip those dependent cards too, log in `## Issues & Flags`.
|
|
2673
|
-
- If no dependency: proceed normally.
|
|
2674
|
-
|
|
2675
|
-
### Post-batch (same as sequential mode)
|
|
2676
|
-
|
|
2677
|
-
After all groups are complete, run the same Final Review, Phase 6 (merge), and Phase 7 (production readiness) as documented above. Since v3.37.0 the Final Review runs a **single FULL `/codexreview` over the entire batch diff** (per the Final-review FULL gate) — no scope reduction — so every team-mode card, including any reviewed at `light` in D.4b, receives a guaranteed full review before merge.
|
|
2678
|
-
|
|
2679
|
-
---
|
|
2680
|
-
|
|
2681
|
-
## Phase 8 — Metrics Log (MONITORING SIGNAL — non-blocking — runs after Phase 7)
|
|
2682
|
-
|
|
2683
|
-
After the Production Readiness Checklist is complete, log this batch run to the skill
|
|
2684
|
-
effectiveness registry. This enables tracking of first-attempt success rate, actionability,
|
|
2685
|
-
and QA quality over time. This is a telemetry write, NOT a gate — it never blocks the batch (see
|
|
2686
|
-
the fail-safe note at the end of the phase). It was previously labelled "MANDATORY", but since it
|
|
2687
|
-
has no blocking consequence the honest label is "monitoring signal".
|
|
2688
|
-
|
|
2689
|
-
**Steps:**
|
|
2690
|
-
|
|
2691
|
-
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:
|
|
2692
|
-
- Start timestamp (from `Started:` field)
|
|
2693
|
-
- Worktree-creation timestamp (from `## Worktree` — the time Phase 0/Pre-flight created the worktree; the strategy-independent cycle-time anchor, see step 2)
|
|
2694
|
-
- Card list and total count
|
|
2695
|
-
- For each completed card:
|
|
2696
|
-
- `fix_cycles` (from the per-phase retry counts logged in `## Completed Cards`)
|
|
2697
|
-
- `qa_profile`, `qa_verdict` (Phase 3.5 step 25 / D.4 QA line)
|
|
2698
|
-
- `qa_first_attempt` (Phase 3.5 step 25 named flag — `pass`/`fail`/`n/a`)
|
|
2699
|
-
- `doc_gaps: found=<N> fixed=<M>` (Phase 3 step 15 / D.4a named counter)
|
|
2700
|
-
- 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`)
|
|
2701
|
-
- Merge commit hash (and, when `git.merge_strategy: pr`, the PR merge timestamp recorded by Phase 6 — see step 2)
|
|
2702
|
-
|
|
2703
|
-
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.
|
|
2704
|
-
|
|
2705
|
-
2. Compute aggregate metrics:
|
|
2706
|
-
- `first_attempt_success_rate`: cards with fix_cycles == 0 / total_cards
|
|
2707
|
-
- `mean_fix_cycles`: mean of per-card fix cycle counts
|
|
2708
|
-
- `qa_profiles`: count of {skip, light, balanced, deep}
|
|
2709
|
-
- `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
|
|
2710
|
-
- `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)
|
|
2711
|
-
- `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)
|
|
2712
|
-
- `severity_p0_pct`: blockers_count / findings_total (0 if no findings)
|
|
2713
|
-
- `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.
|
|
2714
|
-
|
|
2715
|
-
> `$METRICS` = `paths.metrics` from `baldart.config.yml` (default `docs/metrics`). All paths below resolve under `$METRICS` — never a hardcoded `docs/metrics`.
|
|
2716
|
-
|
|
2717
|
-
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:
|
|
2718
|
-
|
|
2719
|
-
```json
|
|
2720
|
-
{"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":""}
|
|
2721
|
-
```
|
|
2722
|
-
|
|
2723
|
-
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.
|
|
2724
|
-
|
|
2725
|
-
4. Copy the batch tracker to archive:
|
|
2726
|
-
|
|
2727
|
-
```bash
|
|
2728
|
-
cp /tmp/batch-tracker-<FIRST-CARD-ID>.md "$METRICS/archive/"
|
|
2729
|
-
```
|
|
2730
|
-
|
|
2731
|
-
5. Note in tracker: `## Metrics Log: WRITTEN (run_id: batch-<FIRST-CARD-ID>)`
|
|
2732
|
-
|
|
2733
|
-
6. **Session token telemetry (ONLY when `STATS=true`)** — if the run was invoked with `-stats` / `--stats`:
|
|
2734
|
-
|
|
2735
|
-
Measure REAL per-role token + wall-clock cost by post-processing the session transcripts (zero model-token cost — runs in Bash). Invoke:
|
|
2736
|
-
|
|
2737
|
-
```bash
|
|
2738
|
-
node .framework/framework/scripts/analyze-session-tokens.js \
|
|
2739
|
-
--skill new --run-id "batch-<FIRST-CARD-ID>" --out-dir "$METRICS"
|
|
2740
|
-
```
|
|
2741
|
-
|
|
2742
|
-
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.
|
|
2743
|
-
|
|
2744
|
-
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.
|
|
2745
|
-
|
|
2746
|
-
**If `$METRICS/skill-runs.jsonl` does not exist**: create it first with `mkdir -p "$METRICS" && touch "$METRICS/skill-runs.jsonl"`.
|
|
2747
|
-
**If batch tracker is missing or unreadable**: log "Metrics Log: SKIPPED (tracker not found)" and proceed without blocking.
|
|
2748
|
-
**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.
|