baldart 4.88.3 → 4.89.1

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,30 @@ 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.89.1] - 2026-07-01
9
+
10
+ **`/new` tracker-write economy — remove the phase-entry write prompts.** An audit (mayo FEAT-0064) measured **20 orchestrator turns whose only tool call was a tracker `Edit`** (~5-11M tokens of pure `cache_read` replay, ~3-6% of the run). The § "Context economy" rule already forbids lone tracker-`Edit` turns (and the metric is trending down: 38 → 28 → 20), so this is a compliance gap, not a missing rule. The non-redundant fix: the per-phase reference modules carried ~9 numbered `**Update tracker**: phase = "X"` **phase-entry** steps (no data) that actively prompt a standalone write, contradicting the global co-emit rule. Removing that prompt at the source is more effective than more prose.
11
+
12
+ **PATCH** — context-economy refinement, no functional behavior change. `/new`-only (`new2` writes its tracker via the JS `ledger()` helper, which costs no orchestrator turn — no parallel change). **No new `baldart.config.yml` key**.
13
+
14
+ ### Changed
15
+
16
+ - **Phase-entry markers removed** across `implement.md` / `review-cycle.md` / `completeness.md` / `commit.md`: the standalone `phase = "1-claim|2-implement|2.55-simplify|2.6-e2e-review|3-doc-review|3.5-qa|2.5-completeness|2.5b-ac-closure|4-commit"` steps are reworded to "**Enter phase X — no standalone tracker write**" pointing at the allowlist. The card-claim (moves the card to `## Current Card`) and the Phase-4 entry-assertion are preserved but explicitly co-emitted. Step numbers are unchanged (no renumbering / no broken cross-refs).
17
+ - **Data-carrying DONE-markers kept** (findings / retry counts / `qa_first_attempt` / AC-closure ledger — Phase-8 telemetry producers), now governed by the allowlist to co-emit with the phase's last tool call.
18
+ - **`SKILL.md` § Context Tracking** gains an explicit **tracker-write allowlist**: the ONLY writes are `phase_module_loaded`, a data-carrying DONE-marker, a commit record, a gate verdict, and a blocker/flag — all co-emitted; there is NO "entering phase X" write. Recovery is unchanged (§ "Context recovery protocol" reconstructs the phase from commit + `phase_module_loaded` + backlog).
19
+
20
+ ## [4.89.0] - 2026-07-01
21
+
22
+ **Mockup-first build routing — a card with a mockup ALWAYS builds via `/ui-implement` → `ui-expert`.** A `/new` post-mortem (mayo FEAT-0064) found two UI cards with a `links.design_src` mockup built by `coder` instead of `ui-expert`, causing layout drift (caught by the v4.78.0 fidelity gate) + three avoidable rework passes + a full `balanced` review (~174M tokens). Root cause: the v4.82.0 `/ui-implement` delegation gate was positioned **inside** `implement.md` step 7's briefing, structurally **subordinate** to the `owner_agent` router (step 6b) — so a card whose `owner_agent` is `coder` (which `prd-card-writer` Rule B correctly assigns to a **mixed UI+logic** card, since `ui-expert` has UI-only scope) resolved `spawn=coder` and the delegation note never fired. `new2.js` was worse: it dispatched `owner_agent` with no delegation gate at all.
23
+
24
+ **MINOR** — routing behavior change, backwards-compatible (no-mockup cards unchanged; the coarse `ui-expert` inline fallback is preserved for Codex / older installs). **No new `baldart.config.yml` key** (rides on the existing `/ui-implement` + `features.has_design_system`) → the schema-change propagation rule does NOT apply.
25
+
26
+ ### Changed
27
+
28
+ - **`implement.md` step 6a (NEW — PRIMARY, precedes the `owner_agent` router)**: a card with `links.design` / `links.design_src` has its BUILD routed **mockup-first** to `/ui-implement` (coarse fallback: force `ui-expert` inline + Phase 2.6), *regardless of `owner_agent`*. The epic guard runs first inside 6a. Step 6b (`owner_agent` router) is now explicitly scoped to cards **without** a mockup; the delegation-gate prose is **retired** from step 7's "### Design Reference" (it lives once, at 6a). `owner_agent` still governs review/ownership semantics.
29
+ - **`new2.js`**: `cardGraph` gains `hasMockup`; the deterministic `OWNER_SPAWN` clamp forces `spawn=ui-expert` (ledger `CLAMPED-TO-UI (mockup-first)`) for a mockup card. new2 keeps its **inline** `ui-expert` build this release (full `/ui-implement` off-context delegation remains the documented follow-up).
30
+ - **`/new` SKILL.md § Agent Routing** + **`prd-card-writer.md` Rule A** + **`design-system-protocol.md`** § "Route-Independent Fidelity" — one aligned note each: the build-agent selection is mockup-first; `owner_agent: coder` on a mixed card means coder owns review/logic semantics, never the UI build. Cited from the single SSOT (implement.md step 6a), not duplicated.
31
+
8
32
  ## [4.88.3] - 2026-07-01
9
33
 
10
34
  **Context-economy trim of the Codex runtime-portability citations.** The top-level RUNTIME PORTABILITY note in `/new` and the HARD-RULES Runtime-portability note in `/prd` (added in v4.88.2's S4/S5 wave) restated content that already lives in `framework/agents/runtime-portability-protocol.md`. Trimmed both to a one-liner (cite, don't restate) — ~406 chars off `/new` SKILL.md and ~363 off `/prd` SKILL.md, i.e. the core each skill drags in context every turn after activation. **No behavior change**: the module citation, the "don't probe `Workflow`/`AskUserQuestion`/the task spine on Codex" rule, and the ADDITIVE guarantee are preserved; RULE 4/11 Codex branches are untouched; the parity guard (`scripts/check-codex-parity.js`) passes. **PATCH.** Skills `new`/`prd` → 1.1.2. No new config key.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.88.3
1
+ 4.89.1
@@ -156,6 +156,16 @@ that list — not this one — is the source of truth.
156
156
  **Epic cards** use `owner_agent: ""` (empty string) because they are
157
157
  trackers, not implementation. The dispatcher skips them.
158
158
 
159
+ > **Mockup-first build (since v4.89.0) — `owner_agent` does NOT gate the build for a
160
+ > card with a mockup.** When a card carries `links.design` / `links.design_src`, `/new`
161
+ > routes its BUILD **mockup-first** to `/ui-implement` → `ui-expert` at `implement.md`
162
+ > step 6a, *regardless of `owner_agent`*. So a **mixed UI+logic card** correctly keeps
163
+ > `owner_agent: coder` (per Rule B — `ui-expert` cannot OWN logic scope) **and still gets
164
+ > its UI built by `ui-expert`**: `owner_agent: coder` here means coder owns the
165
+ > review/logic ownership semantics, it does NOT send the UI build to coder. Keep setting
166
+ > `owner_agent` per Rules A/B as before — just do not expect it to pick the build agent
167
+ > for a mockup card.
168
+
159
169
  ### Rule A.1 — AC↔ownership consistency (every AC must be satisfiable inside the card)
160
170
 
161
171
  For EVERY acceptance criterion you write, the file(s) that AC requires editing
@@ -171,6 +171,7 @@ Trunk branch: [resolved git.trunk_branch — Phase 0 step 0 populates]
171
171
 
172
172
  - **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.
173
173
  - **At card-state-changing boundaries only** (NOT after every sub-step): update the tracker's phase status when something recovery-relevant changes — a commit, a gate verdict, a blocker, a phase-module load. **Always co-emit the `Edit` with that action's tool call** (never a standalone status-only turn — § "Context economy" makes a lone tracker-`Edit` turn a violation). A measured run still paid 38 standalone tracker-Edit turns (~13.6M / ~9%) because "after each phase" was read as "emit a status turn per phase" — so the cadence is deliberately coarsened here: between two real actions there is nothing to write. Fine-grained phase recovery does not depend on per-phase writes — § "Context recovery protocol" reconstructs the current phase from the last commit + `phase_module_loaded` + backlog statuses.
174
+ > **Tracker-write ALLOWLIST (the ONLY events that write the tracker — all co-emitted with their tool call, never a turn of their own):** (a) **`phase_module_loaded`** — folded into the `Read` of the module; (b) a **phase DONE-marker that carries data** (findings / verdict / retry count / `qa_first_attempt` / AC-closure ledger) — folded into the phase's last real tool call; (c) a **commit record** — folded into the commit `Bash`; (d) a **gate verdict** (e2e / codex) — folded into its resolution; (e) a **blocker / flag**. **There is NO "entering phase X" write** — a bare `phase = "<name>"` line with no data and no accompanying action is NOT a tracker trigger (the phase-entry markers were removed from the per-phase modules for exactly this reason). If you are about to `Edit` the tracker with only a phase name, **do not** — the DONE-marker + `phase_module_loaded` + commit already carry recovery.
174
175
  - **After completing a card**: move it from `Current Card` to `## Completed Cards` with:
175
176
  - Commit hash
176
177
  - One-line summary of what was implemented
@@ -427,6 +428,15 @@ orchestrator is hard-killed and never resumed, the `baldart doctor` reaper is th
427
428
 
428
429
  ## Agent Routing (Phase 2 dispatcher)
429
430
 
431
+ > **Mockup-first override (since v4.89.0 — precedes this table).** A card with a
432
+ > mockup (`links.design` / `links.design_src`) does NOT reach the `owner_agent`
433
+ > dispatcher below: its BUILD is routed **mockup-first** at `implement.md` **step 6a**
434
+ > to `/ui-implement` → `ui-expert` (coarse fallback: `ui-expert` inline), *regardless of
435
+ > `owner_agent`*. `owner_agent` still governs review/ownership semantics for that card,
436
+ > but never sends a UI build to `coder`. The table below applies only to cards WITHOUT a
437
+ > mockup. This closes the FEAT-0064 failure (a `owner_agent: coder` mixed card with
438
+ > `links.design_src` built by coder).
439
+
430
440
  Phase 2 reads the card's `owner_agent` field and dispatches to the matching
431
441
  specialist. The enum's single source of truth is the **`owner_agent enum` block in
432
442
  `framework/.claude/agents/REGISTRY.md`** (applied by `prd-card-writer.md § Agent
@@ -6,7 +6,7 @@
6
6
 
7
7
  > 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.
8
8
 
9
- 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 — when `has_toolchain`, the configured `toolchain.commands.{lint,typecheck}` verbatim (§ "Toolchain gates") — (redirect to disk per § "Context economy").
9
+ 26. **Phase 4 entry assertion** (no standalone `phase = "4-commit"` status turn§ "Context Tracking" allowlist; the tracker write for this phase is the commit record at step 29, co-emitted with the commit). **Verify before committing** that 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 — when `has_toolchain`, the configured `toolchain.commands.{lint,typecheck}` verbatim (§ "Toolchain gates") — (redirect to disk per § "Context economy").
10
10
  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.
11
11
  - **IMPORTANT — explicit staging**: NEVER use `git add -A` or `git add .`. Always stage files by explicit name:
12
12
  ```bash
@@ -34,7 +34,7 @@ Before triggering any review, you MUST verify that the coder agent implemented *
34
34
  Also check: if the card has conditional requirements but the completion report has no
35
35
  `conditional_items` section → flag as `Missing` (the coder must document the branch taken).
36
36
 
37
- 1. **Update tracker**: phase = "2.5-completeness".
37
+ 1. **Enter Phase 2.5 (completeness)** — **no standalone tracker write** for phase entry "Context Tracking" allowlist; the tracker records only `2.5-completeness DONE` at step 6, co-emitted). Proceed directly to the next step.
38
38
  2. Re-read the backlog card (`requirements`, `acceptance_criteria`, `unknowns`, and `definition_of_done` fields).
39
39
  3. Build a checklist — one row per item:
40
40
 
@@ -227,7 +227,7 @@ This gate enforces `framework/agents/workflows.md § Scope Closure Discipline` a
227
227
 
228
228
  **Step-by-step**:
229
229
 
230
- 1. **Update tracker**: phase = "2.5b-ac-closure".
230
+ 1. **Enter Phase 2.5b (AC-closure)** — **no standalone tracker write** for phase entry "Context Tracking" allowlist; the tracker records only `2.5b-ac-closure DONE` + the AC Closure Ledger at step 6, co-emitted). Proceed directly to the next step.
231
231
 
232
232
  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):
233
233
 
@@ -3,7 +3,7 @@
3
3
  > **Modulo `/new`** — eseguilo, poi torna al core § "Routing" per la fase successiva. I `§ "..."` (Context economy, Context Tracking, Trivial-card fast-lane, Risk-signal detector, Fix Application Log) vivono nel **core SKILL.md**.
4
4
 
5
5
  ### Phase 1 — Claim & Context
6
- 1. **Update tracker**: set current card, phase = "1-claim".
6
+ 1. **Claim the card** — move it to `## Current Card` in the tracker. **Co-emit this `Edit` with the first real tool call of this phase** (the codebase-architect spawn / the card-YAML `Read`), never as a standalone turn (§ "Context Tracking" allowlist). Do NOT spend a turn on a bare `phase = "1-claim"` status write.
7
7
  2. **`depends_on` gate (BEFORE claiming)** — read the card's `depends_on` field. For each listed card ID:
8
8
  - Read that card's backlog YAML and check its `status` field.
9
9
  - 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). **When AUTONOMOUS (SKILL.md § "AUTONOMOUS RESOLUTION RULE"): do NOT HALT — DAG-exclude this card from the runnable set (defer it) and materialize ONE follow-up card (no-drop); NEVER proceed-anyway, NEVER mark DONE.**
@@ -48,8 +48,37 @@
48
48
  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.
49
49
 
50
50
  ### Phase 2 — Implement (self-healing, up to 3 retries)
51
- 6. **Update tracker**: phase = "2-implement".
52
- 6b. **Agent dispatch (router)** read `owner_agent` from the card YAML and resolve the spawn target per the table in § Agent Routing above:
51
+ 6. **Enter Phase 2 (implement)** — **no standalone tracker write** for phase entry "Context Tracking" allowlist: the phase is recovered from the last commit + `phase_module_loaded` + backlog; the tracker records only `2-implement DONE` at step 11, co-emitted). Proceed directly to 6a.
52
+ 6a. **Mockup-build delegation gate (PRIMARY — precedes the owner_agent router).** The BUILD agent for a card with a mockup is decided by the **mockup**, NOT by `owner_agent`. This gate is structurally FIRST so a stale/mixed-card `owner_agent: coder` can never send a UI build to `coder` (the FEAT-0064 failure: a card with `links.design_src` built by coder because the delegation note was buried downstream in the step-7 briefing). SSOT: `framework/agents/design-system-protocol.md` § "Route-Independent Fidelity & Coverage Obligation".
53
+
54
+ ```
55
+ # 6a is the FIRST dispatch decision. Epic guard FIRST — an epic is a tracker, never built.
56
+ If card is an epic (id ends "-00" OR filename ends "-epic.yml" OR review_profile == "skip"
57
+ with no requirements): SKIP — log "[ROUTER] card <ID> is an epic (tracker) — skipped,
58
+ not implemented" and move to the next card.
59
+ If card has links.design OR links.design_src (a mockup exists):
60
+ IF the /ui-implement skill is available:
61
+ DELEGATE this card's mockup→code implement + fidelity verify to /ui-implement
62
+ in programmatic mode (contract: ui-implement/references/integration.md).
63
+ Consume its COMPACT JSON (status mirrors /e2e-review — review-cycle.md Phase 2.6
64
+ gating table). SKIP step 6b (owner_agent router), the step-7 coarse briefing,
65
+ AND Phase 2.6 (the skill already ran /e2e-review). Then resume the per-card
66
+ review cluster (Phase 2.55 Simplify → Phase 3 doc → 3.5 QA → 3.7 Codex) per the
67
+ card's review_profile — for a MIXED UI+logic card /new KEEPS that cluster
68
+ (integration.md § "What /new KEEPS"); it is fidelity-only that the skill owns.
69
+ ELSE (coarse fallback — Codex without the skill / older install / no skill routing):
70
+ FORCE spawn = "ui-expert", briefing = "ui-expert" (regardless of owner_agent),
71
+ and run Phase 2.6 /e2e-review inline as before. The step-7 "### Design Reference"
72
+ section is the coarse briefing body.
73
+ Log (tracker): "[ROUTER] card <ID> has a mockup (links.design[_src]) → mockup-first
74
+ build via /ui-implement (or ui-expert coarse); owner_agent='<raw>' does NOT gate
75
+ the build".
76
+ → the build agent for this card is now decided; do NOT fall through to step 6b.
77
+ Else (no mockup) → fall through to step 6b (owner_agent router).
78
+ ```
79
+
80
+ `owner_agent` is still honored for **review/ownership semantics** (AC-closure ownership, `security-reviewer` relevance, the mixed-card review cluster) — it simply no longer decides the BUILD agent when a mockup is present.
81
+ 6b. **Agent dispatch (router — cards WITHOUT a mockup only).** Reached only when step 6a did not fire (the card has no `links.design`/`links.design_src`). Read `owner_agent` from the card YAML and resolve the spawn target per the table in § Agent Routing above:
53
82
 
54
83
  ```
55
84
  Let raw = card.owner_agent (string, may be missing).
@@ -113,22 +142,13 @@
113
142
  Design file: [path from card's links.design field]
114
143
  Design source: [path from card's links.design_src field, if present]
115
144
 
116
- **DELEGATION GATE mockup→code is owned by `/ui-implement` (since v4.82.0).**
117
- When the `/ui-implement` skill is available AND the card has `links.design` /
118
- `links.design_src`, the orchestrator DELEGATES this card's mockup→code
119
- **implement + fidelity verify** to `/ui-implement` in programmatic mode
120
- (contract: `framework/.claude/skills/ui-implement/references/integration.md`).
121
- The skill is the SSOT of the input-type build playbook (Claude Design link /
122
- finished-code / image / HTML) and folds in Phase 2.6 `/e2e-review`. On delegation: **skip the
123
- coarse briefing below AND Phase 2.6 for this card** (the skill already ran the
124
- fidelity verify), consume its COMPACT JSON, then resume the normal per-card
125
- cluster on the resulting diff (Phase 2.55 Simplify → **skip Phase 2.6** which
126
- the skill already ran → Phase 3 doc / 3.5 QA / 3.7 Codex — the skill's scope is
127
- **fidelity only**, no review hole). The `ui-expert` registry-first cascade +
128
- Post-Intervention Coherence below STILL apply — the skill enforces the same
129
- SSOTs. **Coarse inline fallback** (skill unavailable / Codex / older install):
130
- use the briefing below + Phase 2.6 as before; the prose here stays the SSOT
131
- fallback (delegate-or-else-inline).
145
+ > **Note:** the mockup→code build decision was made at **step 6a** (Mockup-build
146
+ > delegation gate). If step 6a delegated to `/ui-implement`, this whole
147
+ > "### Design Reference" section is NOT reached (the skill owns the build + Phase
148
+ > 2.6). This section is the **coarse-fallback briefing body** filled by step 6a's
149
+ > ELSE branch (skill unavailable → `ui-expert` builds inline + Phase 2.6 runs). Its
150
+ > SSOT is `ui-implement/references/playbook.md` + `ui-expert.md`; do NOT re-add a
151
+ > delegation gate here it lives once, at step 6a.
132
152
 
133
153
  **Coarse fallback — build workflow by input type.** The full SSOT is
134
154
  `framework/.claude/skills/ui-implement/references/playbook.md` +
@@ -124,7 +124,7 @@ After completeness is verified, clean up the implementation before it reaches re
124
124
 
125
125
  **Step-by-step**:
126
126
 
127
- 1. **Update tracker**: phase = "2.55-simplify".
127
+ 1. **Enter Phase 2.55 (simplify)** — **no standalone tracker write** for phase entry "Context Tracking" allowlist; the tracker records only `2.55-simplify DONE` at step 6, co-emitted). Proceed directly to step 2.
128
128
  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).
129
129
  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:
130
130
 
@@ -200,7 +200,7 @@ auto-skips on backend-only cards, and BLOCKS the commit on gating findings.
200
200
  When the gate above passes, the orchestrator invokes `/e2e-review` in
201
201
  **programmatic mode**:
202
202
 
203
- 1. **Update tracker**: phase = "2.6-e2e-review".
203
+ 1. **Enter Phase 2.6 (e2e-review)** — **no standalone tracker write** for phase entry "Context Tracking" allowlist; the tracker records only the e2e gate verdict, co-emitted with its resolution). Proceed directly to step 2.
204
204
  2. Spawn the skill with the payload:
205
205
 
206
206
  ```json
@@ -284,7 +284,7 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
284
284
 
285
285
  > **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`.
286
286
 
287
- 12. **Update tracker**: phase = "3-doc-review".
287
+ 12. **Enter Phase 3 (doc-review)** — **no standalone tracker write** for phase entry "Context Tracking" allowlist; the tracker records only `3-doc-review DONE` at step 17, co-emitted). Proceed directly to the next step.
288
288
  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):
289
289
  ```bash
290
290
  git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD
@@ -346,7 +346,7 @@ skill's Phase 1 falls back to deriving Gherkin scenarios from
346
346
 
347
347
  ### Phase 3.5 — QA Validation
348
348
 
349
- 18. **Update tracker**: phase = "3.5-qa".
349
+ 18. **Enter Phase 3.5 (QA)** — **no standalone tracker write** for phase entry "Context Tracking" allowlist; the tracker records only `3.5-qa DONE` at step 25, co-emitted, incl. the `qa_first_attempt` producer). Proceed directly to step 19.
350
350
  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).
351
351
  20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
352
352
  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.
@@ -286,7 +286,7 @@ try {
286
286
  g3Bullet +
287
287
  `• G4 card-field validation (setup.md 1b/1c, card-schema.md consumer contract): card missing acceptance_criteria/files_likely_touched/scope → EXCLUDE (excluded[] + reason). \`requirements\` is CONDITIONAL, not an auto-exclude: if it is missing BUT acceptance_criteria + scope are both present and non-empty, FAITHFULLY DERIVE it (a concrete restatement/decomposition of the existing AC + scope — faithful, never inventing new scope) and WRITE it back to the card YAML on disk in ${MAIN}/${paths.backlog_dir || 'backlog'} (F-040: main repo, not the worktree copy; the card artifact is NOT a source/doc file, so this is allowed despite the role boundary), logging \`[BACKFILL] <id>: requirements=<N items, AC+scope-derived>\`. Only EXCLUDE for missing requirements when acceptance_criteria OR scope is ALSO empty (a genuinely thin card). Never HALT for one bad card.\n` +
288
288
  `• G5 depends-on: a card whose depends_on names a non-DONE card NOT in this batch → EXCLUDE it AND every in-batch card that transitively depends on it.\n` +
289
- `• cardGraph (REQUIRED, F-021): for every runnable card return { id, dependsOn:[IN-BATCH deps only], ownerAgent (the card's owner_agent; G25 unknown→'coder'), reviewProfile (the card's review_profile; default 'balanced'), policyDeferredACs, alreadyCommitted, alreadyCommittedSha, isEpic (implement.md §6b epic guard: id ends '-00' OR filename ends '-epic.yml' OR group.is_epic:true OR review_profile 'skip' with no requirements), filesLikelyTouched (verbatim from the YAML) }.\n` +
289
+ `• cardGraph (REQUIRED, F-021): for every runnable card return { id, dependsOn:[IN-BATCH deps only], ownerAgent (the card's owner_agent; G25 unknown→'coder'), hasMockup (BOOLEAN — true IFF the card has a non-empty links.design OR links.design_src; drives the mockup-first build override — implement.md §6a), reviewProfile (the card's review_profile; default 'balanced'), policyDeferredACs, alreadyCommitted, alreadyCommittedSha, isEpic (implement.md §6b epic guard: id ends '-00' OR filename ends '-epic.yml' OR group.is_epic:true OR review_profile 'skip' with no requirements), filesLikelyTouched (verbatim from the YAML) }.\n` +
290
290
  `• B1/F-026 idempotency (per card, AFTER the worktree exists): set alreadyCommitted:true (+ alreadyCommittedSha) IFF ALL hold: (a) a commit referencing the card id exists in ${TRUNK}..HEAD of the worktree; (b) the card's validation_commands re-run GREEN right now; (c) NO open follow-up card for it exists in ${paths.backlog_dir || 'backlog'}. On a FRESH worktree ${TRUNK}..HEAD is empty → all false, zero extra work.\n` +
291
291
  `• F-016 AC↔ownership consistency: for each acceptance_criterion, derive the file(s) it requires editing. If those files are NOT a subset of the card's MAY-EDIT/files_likely_touched → add the AC to policyDeferredACs:[{n,text,owningCard|owningFile,reason}] (it will become ONE follow-up, never a resolve). Do the same for any AC whose remedy is an owner-gated infra action (remote db push / deploy / secret / DNS).\n` +
292
292
  (migrationApplied
@@ -370,6 +370,16 @@ for (const n of cardGraph) graphById[n.id] = n
370
370
  const OWNER_SPAWN = { coder: 'coder', 'ui-expert': 'ui-expert' }
371
371
  for (const n of cardGraph) {
372
372
  const raw = String(n.ownerAgent || '').trim()
373
+ // Mockup-first override (implement.md §6a, since v4.89.0): a card with a mockup builds
374
+ // via ui-expert regardless of owner_agent — closes the FEAT-0064 coder-builds-UI failure.
375
+ // (new2 keeps the INLINE ui-expert build this release; full /ui-implement off-context
376
+ // delegation is the documented follow-up — ui-implement/references/integration.md § new2 note.)
377
+ if (n.hasMockup) {
378
+ n.ownerAgentRaw = raw
379
+ n.ownerAgent = 'ui-expert'
380
+ ledger(n.id, 'router', 'CLAMPED-TO-UI', `mockup-first: links.design[_src] present → spawn=ui-expert (owner_agent='${raw || '(missing)'}' does not gate the build)`)
381
+ continue
382
+ }
373
383
  const spawn = OWNER_SPAWN[raw.toLowerCase()] || 'coder'
374
384
  n.ownerAgentRaw = raw
375
385
  n.ownerAgent = spawn
@@ -645,6 +645,15 @@ advisory), plus the mechanical build/lint/tsc gates. The deep `/codexreview` and
645
645
  layout) is absorbed by the trio. All fidelity fixes (structural, presentational, quality)
646
646
  route to `ui-expert`.
647
647
 
648
+ **BUILD-agent selection is mockup-first (since v4.89.0).** For ANY card with a mockup
649
+ (`links.design` / `links.design_src`) — pure-graphics OR **mixed UI+logic** — the build
650
+ agent is decided by the mockup, NOT `owner_agent`: it is routed to `/ui-implement` →
651
+ `ui-expert` **before and independent of** the `owner_agent` router (`/new` `implement.md`
652
+ step 6a; `new2.js` mockup-first clamp). This closes the FEAT-0064 failure where a mixed
653
+ card's `owner_agent: coder` (correct for its logic/review ownership) sent the UI build to
654
+ `coder`. `owner_agent` still governs the review/ownership semantics; it just does not pick
655
+ the build agent when a mockup is present.
656
+
648
657
  ### Gating philosophy (calibration)
649
658
 
650
659
  Vision-model reliability research (*MLLM as a UI Judge*, 2025) shows multimodal judges are
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.88.3",
3
+ "version": "4.89.1",
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"