baldart 4.11.0 → 4.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.12.0] - 2026-06-04
9
+
10
+ **`/new` non gonfia più il context dell'orchestrator su long-run — il bulk content (log dei gate, `git diff`, file interi, baseline) non scorre più nel canale inline dell'orchestrator: vive su disco e viaggia per *path*.** Sintomo riportato dall'utente: su batch lunghi il consumo si impennava per il context bloat. Una prima ipotesi (i *finding* delle review che tornano inline + un card-runner sub-agent isolato + un "context purge" da rinforzare) è stata **sottoposta a review avversariale e refutata**: (1) l'orchestrator DEVE leggere il contenuto dei finding ai punti-decisione (domain-override partition, AC-Closure, `NEEDS_MANUAL_CONFIRMATION`, merge/dedup del Final gate) → un contratto "verdict-only" che li nasconde romperebbe la skill e i consumer condivisi (`/prd`, `/codexreview`); (2) un card-runner sub-agent non può ospitare i gate utente né garantire il nested-spawn dei reviewer; (3) un "compaction-lossless checkpoint" non regge (`/tmp` è single-point-of-failure, l'auto-compact non è controllabile da una skill). La verifica sul codice ha trovato che **il vero driver del bloat è il bulk content reso inline nei tool-result dell'orchestrator stesso**, non i finding: output dei gate `lint`/`tsc`/`test`/`build` (resi inline da `| tee`, ~40-50%), `git diff` completo passato inline ai simplify agent (~25-30%), Read di file interi nel completeness check, e baseline concatenati nel Final F.3. **MINOR** (cambia il comportamento di esecuzione di `/new`; nessuna nuova capability, nessun nuovo agente, nessuna chiave `baldart.config.yml`, nessun contratto di return degli agent toccato — la schema-propagation rule non si applica).
11
+
12
+ > **Why.** L'orchestrator di `/new` è un unico contesto long-lived su tutto il batch: ogni byte che rende inline (Bash tool-result, prompt che compone, file che Read-a) resta in finestra per l'intero run, e nessun "purge" via prompt recupera token. La fix attacca la radice — **tenere il bulk fuori dal canale inline** — senza toccare ciò che l'orchestrator può leggere ai punti-decisione (i finding restano file-resident e leggibili on-demand). Onestà sui limiti: questo riduce il *rate di accumulo* (stima ~40-50% sul footprint dominante), non azzera la crescita del context; il bound vero richiederebbe isolamento per-card a livello di harness, fuori dalla portata di una skill.
13
+
14
+ ### Changed
15
+
16
+ - **`framework/.claude/skills/new/SKILL.md`** — nuova sezione SSOT **`## Context economy (MANDATORY)`** (HARD RULE in 5 punti: gate-output discipline, diff-to-disk, findings file-resident, pass-paths-not-concatenations, targeted Reads). Applicata ai siti che la violavano:
17
+ - **Gate bash (Phase 2 step 8)** — `cmd 2>&1 | tee /tmp/x.txt` → `cmd > /tmp/x.txt 2>&1; echo "<gate>:$?"`: l'output completo resta su disco, inline solo l'exit code; su fallimento si legge un estratto *bounded* (`tail -n 30`), mai il log intero. Step 9 passa al fix agent il **path** del log, non il blob.
18
+ - **Tutti i re-run di gate foreground** (gap-fix Phase 2.5, Phase 2.55 step 5, Phase 3 step 16, pre-commit Phase 4, Final F.5, team D.1/D.3b) — pointer alla disciplina (redirect a disco, mai inline).
19
+ - **`git diff` (Phase 2.55 step 2-3)** — `git diff > /tmp/diff-<CARD>.txt`; i 3 simplify agent ricevono il **path** e leggono il diff da soli, niente «full diff» nei prompt. Team D.3b allineato.
20
+ - **Blocchi Codex (Phase 0 cross-card audit, Final F.3)** — `2>&1 | tee "$FILE"` → `> "$FILE" 2>&1` (niente copia inline; il file si riempie comunque in streaming per il polling F.4, commento aggiornato).
21
+ - **Final F.3 baseline** — `${ARCH_BASELINE}` (contenuti concatenati) → `${ARCH_BASELINE_PATHS}` (lista di path che Codex Read-a on-demand); F.2 non concatena più i per-card baseline.
22
+ - **Completeness check (Phase 2.5 step 4)** — Read *mirati* (grep con `offset`/`limit` stretti attorno al `file:line` del completion report) invece di Read di file interi.
23
+ - **Progress Bar** — blocco markdown completo solo alle boundary pesanti (card/wave/gate-decision/STOP); il movimento di fase intra-card si mostra via Task spine sub-state, non ri-emettendo la tabella a ogni fase.
24
+ - **Phase 5 step 31** — il "CONTEXT PURGE" è ri-etichettato come *reference-hygiene* (non token-reclamation, che un prompt non può ottenere); il leverage reale è upstream (la § Context economy tiene il bulk fuori dal context fin dall'inizio).
25
+
8
26
  ## [4.11.0] - 2026-06-04
9
27
 
10
28
  **Gli overlay non costringono più a riconciliare a ogni `baldart update` — la VERSION non è più incisa nell'identità dei file generati né usata come segnale di drift quando il base file non è cambiato.** Sintomo riportato dall'utente: ogni update richiedeva una riconciliazione. La verifica del sorgente ha trovato **due trigger indipendenti con la stessa radice** — la VERSION del framework veniva trattata come parte dell'identità di overlay/file-generati, ma viene bumpata a *ogni* release a prescindere dal fatto che lo specifico base file sia cambiato. **(A) churn dei file agent/command generati:** `buildMarker()` stampava `base_version=<VERSION>` nel commento `<!-- baldart-generated -->`; a ogni update la VERSION cambiava → la riga del marker cambiava anche su contenuto byte-identico → git vedeva un diff → scattava il commit `post-update reconcile` *a ogni update*. Il campo era puramente informativo (`readMarker` lo leggeva ma nessuno gate-ava la rigenerazione su di esso). **(B) falso-drift degli skill overlay:** `doctor` e `status` confrontavano il pin `base_skill_version` *direttamente* con la VERSION installata (ignorando `base_file_sha`), così ogni bump faceva apparire ogni overlay come "drifted" anche con base SKILL.md identico — mentre `overlay drift` lo faceva già correttamente SHA-first. **MINOR** (cambia il formato del marker generato; nessuna chiave `baldart.config.yml` — la fix riusa `base_file_sha` già presente).
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.11.0
1
+ 4.12.0
@@ -167,7 +167,7 @@ In team mode the cards of a wave run in parallel: set ALL of a wave's card tasks
167
167
 
168
168
  ### B. Progress Bar — markdown, at transition boundaries
169
169
 
170
- Append this block to your message **at every transition boundary** (NOT on every message — that would be noise across long autonomous runs). A **transition boundary** is any of: a phase change, a wave change, a card change, **any gate decision** (resolved or skipped), and every `AskUserQuestion` / STOP.
170
+ Append this block to your message **at the heavy transition boundaries only** (NOT on every message, and NOT on every intra-card phase change — that accumulates markdown across long autonomous runs; per § "Context economy"). A **heavy transition boundary** is any of: a **card change**, a **wave change**, **any gate decision** (resolved or skipped), and every `AskUserQuestion` / STOP. **Intra-card phase movement** (e.g. Phase 2 → 2.5 → 2.55 within the same card, with no gate decision) is shown via the **Task spine live sub-state** (TaskUpdate, § A above) — NOT by re-emitting this full markdown block each phase.
171
171
 
172
172
  ```
173
173
  ---
@@ -204,6 +204,39 @@ In **team mode** the same gates map to the per-card team sub-steps (D.3a AC-Clos
204
204
 
205
205
  ---
206
206
 
207
+ ## Context economy (MANDATORY)
208
+
209
+ `/new` runs as a single long-lived orchestrator across a whole batch. Every byte the orchestrator
210
+ renders inline (Bash tool-results, agent prompts it composes, files it Reads) stays in its context
211
+ window for the **entire** run — there is no real "purge" (the soft "forget" instruction does not
212
+ reclaim tokens). On long batches the dominant token cost is **bulk content the orchestrator pipes
213
+ through its own inline channel**: gate logs, full `git diff`s, whole-file Reads, concatenated
214
+ baselines. Keep that bulk on disk and pass **paths**, not bodies.
215
+
216
+ > **HARD RULE — bulk content never streams inline.**
217
+ > 1. **Gate-output discipline.** Never run a verification gate (`lint` / `tsc` / `test` / `build`)
218
+ > with its output streaming inline — **never `| tee`, never a bare `npm run …`**. Always
219
+ > `cmd > /tmp/<gate>-<CARD-ID>.txt 2>&1` and surface only the exit code inline (`echo "<gate>:$?"`).
220
+ > On failure, surface a **bounded** extract only (`tail -n 30` or `grep -Ei 'error|fail' … | head -n 30`),
221
+ > never the whole log. Pass any fix agent the **file path**, not the inline blob.
222
+ > 2. **Diffs to disk.** Capture `git diff` to `/tmp/diff-<CARD-ID>.txt` and pass agents that path —
223
+ > never paste a full diff into a prompt or render it inline. (`git diff --name-only` file *lists*
224
+ > are fine — they are small.)
225
+ > 3. **Findings stay file-resident.** Reviewer findings already live in their report files
226
+ > (`/qa/*.md`, `/tmp/codexreview-*.md`). Read a findings file only at the decision point that needs
227
+ > it (merge / domain-route / severity tally) — do not echo finding bodies back into your messages.
228
+ > 4. **Pass baseline/report paths, not concatenations.** When briefing a downstream reviewer
229
+ > (e.g. Codex), give it the **list of baseline/report paths** to read on demand rather than
230
+ > inlining their concatenated contents.
231
+ > 5. **Targeted Reads.** When verifying code (Phase 2.5), Read only the evidence lines (grep with
232
+ > tight context around the `file:line` the completion report names) — not whole files.
233
+ >
234
+ > This rule is purely about the **inline channel**. It does NOT change any agent's return contract,
235
+ > nor what the orchestrator is allowed to read at a decision point — only that bulk arrives via a
236
+ > path the consumer opens itself, not via the orchestrator's own context.
237
+
238
+ ---
239
+
207
240
  ## Phase 0 — Workspace Hygiene Pre-flight (BLOCKING — non-skippable)
208
241
 
209
242
  **Why this exists**: FEAT-0006 incident left the main repo with an unpushed orphan commit (`c9d41f9`) and `develop` diverged from `origin/develop` because `/new` started work on a dirty/diverged repo without surfacing the situation. This phase reconciles the main repo state BEFORE any worktree is created, and snapshots any in-progress user work so Phase 6c can restore it after the batch.
@@ -376,7 +409,7 @@ In **team mode** the same gates map to the per-card team sub-steps (D.3a AC-Clos
376
409
  ```bash
377
410
  AUDIT_FILE="/tmp/codex-crosscard-<FIRST-CARD-ID>-<SESSION-ID>.md" && \
378
411
  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)" && \
379
- [ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" | tee "$AUDIT_FILE" && exit 1; \
412
+ [ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" > "$AUDIT_FILE" && exit 1; \
380
413
  node "$CODEX_SCRIPT" task --wait "
381
414
  Cross-card grounding check for a batch of backlog cards about to be implemented together.
382
415
  Your job is to find conflicts BETWEEN cards that per-card reviewers would miss.
@@ -405,7 +438,7 @@ In **team mode** the same gates map to the per-card team sub-steps (D.3a AC-Clos
405
438
  - **Fix**: concrete recommendation (add depends_on, force sequential, etc.)
406
439
 
407
440
  If no cross-card conflicts: return PASS.
408
- " 2>&1 | tee "$AUDIT_FILE"
441
+ " > "$AUDIT_FILE" 2>&1
409
442
  ```
410
443
 
411
444
  **Variable interpolation**:
@@ -885,20 +918,20 @@ For each card, execute these phases in order:
885
918
  field with the exact file path and line where the TODO comment was written.
886
919
  ```
887
920
 
888
- 8. **Run the verification gates and CAPTURE their output** (so step 9 can pass it to a fix agent). Each is its own gate:
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:
889
922
  ```bash
890
923
  cd <worktree-path>
891
- npm run lint 2>&1 | tee /tmp/lint-<CARD-ID>.txt
924
+ npm run lint > /tmp/lint-<CARD-ID>.txt 2>&1; echo "lint:$?"
892
925
  # tsc is its OWN blocking gate — run it ONLY when stack.language includes "typescript"
893
926
  # (do NOT assume `npm run build` covers tsc — Next.js dev builds and many setups skip it):
894
- npx tsc --noEmit 2>&1 | tee /tmp/tsc-<CARD-ID>.txt # guard: when stack.language includes "typescript"
895
- npm test 2>&1 | tee /tmp/test-<CARD-ID>.txt # if tests exist
896
- npm run build 2>&1 | tee /tmp/build-<CARD-ID>.txt
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:$?"
897
930
  ```
898
- When `stack.language` does NOT include `typescript`, skip the `tsc` line (no equivalent gate). Capturing to `/tmp/*-<CARD-ID>.txt` guarantees the failing output is available for step 9 — do NOT run the gates without capture.
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.
899
932
  9. **If any check fails**: categorize the error (`lint | TypeScript | test | build`), log it in the tracker as `retry-cause: <category>`.
900
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.
901
- When spawning a fix agent: scope it exclusively to this card's Edit-allowed files (from `## File Ownership Map`) — it MUST NOT touch files owned by other cards. Pass the fix agent: the error output (from the captured `/tmp/*-<CARD-ID>.txt` files), the error category, the explicit list of files it may edit, and the failing check output. Do NOT ask the user — just fix and re-run. Fix the code, not the tests (unless the test itself is wrong). Repeat up to **3 times**. **Stuck-loop guard**: compare the failing error's fingerprint (file:line + message) between retries; if the SAME error reproduces on 2 consecutive retries, the fix is not converging (often a constraint outside the card's ownership map) — stop early, log `[STUCK-LOOP] <error>` in `## Issues & Flags`, and escalate to the user rather than burning the 3rd retry on an identical failure.
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.
902
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.
903
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).
904
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:
@@ -950,8 +983,12 @@ Before triggering any review, you MUST verify that the coder agent implemented *
950
983
  | 2 | [acceptance criterion] | Done / Missing / Partial | [file:line or "not found"] |
951
984
  ```
952
985
 
953
- 4. For each item, verify by **reading the actual implementation code** (use Grep/Read).
954
- Do NOT trust the coder agent's completion report alone verify independently.
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.
955
992
 
956
993
  **Verification depth per requirement type:**
957
994
  - **"Create endpoint/route"** → verify: route file exists, handler has correct HTTP method,
@@ -1023,7 +1060,7 @@ Before triggering any review, you MUST verify that the coder agent implemented *
1023
1060
  - The exact list of unimplemented items (copy the checklist rows)
1024
1061
  - The file-ownership restrictions from `## File Ownership Map`
1025
1062
  - The instruction: "Implement ONLY these missing items. Do not refactor or expand scope."
1026
- - 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).
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).
1027
1064
  - Re-verify each fixed item against the code — do NOT trust the agent's self-report.
1028
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:
1029
1066
  - Log in `## Issues & Flags`: list each unimplemented requirement.
@@ -1238,8 +1275,8 @@ After completeness is verified, clean up the implementation before it reaches re
1238
1275
  **Step-by-step**:
1239
1276
 
1240
1277
  1. **Update tracker**: phase = "2.55-simplify".
1241
- 2. Run `git diff` in the worktree to capture all changes for the current card.
1242
- 3. Launch **three agents in parallel** (single message, all receive the full diff):
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:
1243
1280
 
1244
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.
1245
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).
@@ -1252,7 +1289,7 @@ After completeness is verified, clean up the implementation before it reaches re
1252
1289
 
1253
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>`.
1254
1291
 
1255
- 5. After all fixes, run `npm run lint` and `npx tsc --noEmit` to confirm nothing broke.
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).
1256
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.
1257
1294
 
1258
1295
  6. **Update tracker**: phase = "2.55-simplify DONE", log count of fixes applied (or "clean — 0 fixes").
@@ -1423,7 +1460,7 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
1423
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.
1424
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.
1425
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.)
1426
- 16. Run `npm run lint` and `npx tsc --noEmit` (when `stack.language` includes typescript) to verify nothing broke. If doc-reviewer touched any source-adjacent file (a `.ts`/`.tsx` helper, a co-located doc export), also run `npm run build`. If any check fails, apply the self-healing retry loop (up to 3 times, no user prompt). **If still failing after 3 retries**: do NOT fall through silently to Phase 3.5 — log `[DOC-PHASE-REGRESSION]` in `## Issues & Flags` and invoke `AskUserQuestion` (revert the doc-phase edits that broke the build / keep and fix manually / stop the card).
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).
1427
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.
1428
1465
  If doc-reviewer found a recurring gap, append 1-line to `## Lessons Learned`:
1429
1466
  `DOC: <pattern>`
@@ -1645,7 +1682,7 @@ The detector (Step A) is bash + grep — guaranteed to run, no LLM skip. The dow
1645
1682
 
1646
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.
1647
1684
 
1648
- 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.
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").
1649
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.
1650
1687
  - **IMPORTANT — explicit staging**: NEVER use `git add -A` or `git add .`. Always stage files by explicit name:
1651
1688
  ```bash
@@ -1689,7 +1726,7 @@ Never block the pipeline indefinitely — recover and continue per the rules abo
1689
1726
 
1690
1727
  ### Phase 5 — Context Clean & Continue
1691
1728
  30. Archive the card from Active Code Context in `${paths.references_dir}/project-status.md`.
1692
- 31. **CONTEXT PURGE**: After updating the tracker, deliberately forget the implementation details of this card. From this point forward, you should NOT reference any code, file contents, or review details from this cardonly the summary in the tracker. If you need to recall what happened, read the tracker file. This keeps your working context lean for the next card.
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".
1693
1730
  32. **Update tracker**: clear `## Current Card`, move to next pending card.
1694
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**.
1695
1732
 
@@ -1749,14 +1786,16 @@ Once ALL cards are committed in the worktree:
1749
1786
  for c in <ALL-CARD-IDS>; do [ -s "/tmp/arch-baseline-$c.md" ] || MISSING+=("$c"); done
1750
1787
  printf '%s\n' "${MISSING[@]}"
1751
1788
  ```
1752
- - **All present** → do NOT re-spawn the architect for the full batch. Concatenate the per-card
1753
- baselines into `${ARCH_BASELINE}` (they already cover every touched file across the batch) and
1754
- proceed to F.3. Log `f.2-arch: reused N per-card baselines (no re-spawn)` in the tracker. This
1755
- avoids the N+1 architect invocations the per-card persistence was designed to prevent.
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.
1756
1795
  - **Any missing** (a card was added late, or a baseline was purged) → invoke **codebase-architect**
1757
1796
  ONCE over the batch scope to map existing architecture, critical patterns, and high-risk code
1758
- paths for regression. Persist its output to `/tmp/arch-baseline-batch-<FIRST-CARD-ID>.md` and use
1759
- that as `${ARCH_BASELINE}`. Log `f.2-arch: re-spawned (missing baselines: <list>)`. Do NOT spawn
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
1760
1799
  the architect more than once for the batch — it is the single grounding context for all
1761
1800
  downstream review agents.
1762
1801
 
@@ -1764,12 +1803,12 @@ Once ALL cards are committed in the worktree:
1764
1803
 
1765
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.
1766
1805
 
1767
- 6. **Launch Codex code review** via `Bash` with `run_in_background: true` and `timeout: 600000` (10 min). **The companion script is invoked WITHOUT `--wait`** so the Bash call returns immediately and the orchestrator can fire the parallel Claude agents in step 7; poll `$REVIEW_FILE` for completion in F.4 (it is `tee`-d, so it fills as Codex runs and is complete when the background task finishes). Combining `run_in_background: true` with `--wait` would block the shell and defeat the parallelism — do NOT pass `--wait` here.
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.
1768
1807
 
1769
1808
  ```bash
1770
1809
  REVIEW_FILE="/tmp/codexreview-batch-<FIRST-CARD-ID>-<SESSION-ID>.md" && \
1771
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)" && \
1772
- [ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" | tee "$REVIEW_FILE" && exit 1; \
1811
+ [ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" > "$REVIEW_FILE" && exit 1; \
1773
1812
  node "$CODEX_SCRIPT" task "
1774
1813
  Run a deep multi-agent code review for these backlog cards. This is a post-implementation
1775
1814
  review — the code is already written and committed. Your job is to find bugs, regressions,
@@ -1781,8 +1820,8 @@ Once ALL cards are committed in the worktree:
1781
1820
  Files changed (review ALL of these):
1782
1821
  ${REVIEW_SCOPE_FILES}
1783
1822
 
1784
- Architecture baseline (from codebase-architect):
1785
- ${ARCH_BASELINE}
1823
+ Architecture baseline files (read each — they hold file paths, type signatures, patterns, high-risk paths):
1824
+ ${ARCH_BASELINE_PATHS}
1786
1825
 
1787
1826
  Follow the /codexreview protocol:
1788
1827
  1. For each card, read its backlog YAML for acceptance_criteria and entrypoints.
@@ -1803,13 +1842,13 @@ Once ALL cards are committed in the worktree:
1803
1842
  6. Classify surviving findings as VERIFIED, FALSE_POSITIVE, or NEEDS_MANUAL_CONFIRMATION.
1804
1843
 
1805
1844
  Return ONLY verified findings. If zero verified bugs: state 'No verified bugs found.'
1806
- " 2>&1 | tee "$REVIEW_FILE"
1845
+ " > "$REVIEW_FILE" 2>&1
1807
1846
  ```
1808
1847
 
1809
1848
  **Variable interpolation** (build the command string before execution):
1810
1849
  - `${CARD_PATHS}`: newline-separated list of backlog YAML paths
1811
1850
  - `${REVIEW_SCOPE_FILES}`: newline-separated list from Step F.1
1812
- - `${ARCH_BASELINE}`: key findings from Step F.2 (2-3 paragraphs max)
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)
1813
1852
 
1814
1853
  7. **In parallel with Codex**, launch Claude support agents (single message):
1815
1854
 
@@ -1858,7 +1897,7 @@ Once ALL cards are committed in the worktree:
1858
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.
1859
1898
  - **All remaining findings** (other code, perf, test) → invoke the **coder** agent once to apply them in a single pass.
1860
1899
  Run in the order doc-reviewer → coder (or skip either if its partition is empty). Pass only the verified findings, not false positives.
1861
- 12. Run final build: `npm run lint && npx tsc --noEmit && npm run build`.
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).
1862
1901
  If any check fails, apply self-healing retry loop (up to 3 times).
1863
1902
  13. **Update tracker** with final review results:
1864
1903
  - Review engine: Codex (a non-Anthropic frontier model, resolved at runtime by `codex-companion.mjs`) (primary) | Claude code-reviewer (fallback)
@@ -2538,7 +2577,7 @@ For each completed agent:
2538
2577
 
2539
2578
  After ALL agents in the group complete successfully:
2540
2579
 
2541
- 1. **D.1 — Build verification (group)** — Run `npm run build` in the worktree to verify combined changes compile. If build fails, identify which card's changes broke it (from `git diff` per card), spawn a targeted fix-coder for those files only.
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.
2542
2581
 
2543
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:
2544
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).
@@ -2559,7 +2598,7 @@ After ALL agents in the group complete successfully:
2559
2598
 
2560
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.
2561
2600
 
2562
- 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) scoped to that card's diff (`git diff --name-only` filtered by the card's File Ownership Map). 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. (Concurrency is capped by the platform; passing N cards is safe — excess agents queue.)
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.)
2563
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.)
2564
2603
 
2565
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.11.0",
3
+ "version": "4.12.0",
4
4
  "description": "Claude Agent Framework - Reusable framework for coordinating AI agents and humans in software projects",
5
5
  "bin": {
6
6
  "baldart": "./bin/baldart.js"