baldart 5.4.1 → 5.6.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.
Files changed (32) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/VERSION +1 -1
  3. package/framework/.claude/agents/CHANGELOG.md +16 -0
  4. package/framework/.claude/agents/prd-card-writer.md +37 -3
  5. package/framework/.claude/skills/new/CHANGELOG.md +33 -0
  6. package/framework/.claude/skills/new/SKILL.md +11 -5
  7. package/framework/.claude/skills/new/references/commit.md +12 -8
  8. package/framework/.claude/skills/new/references/completeness.md +10 -0
  9. package/framework/.claude/skills/new/references/final-review.md +23 -0
  10. package/framework/.claude/skills/new/references/implement.md +14 -4
  11. package/framework/.claude/skills/new/references/merge-cleanup.md +35 -14
  12. package/framework/.claude/skills/new/references/setup.md +1 -1
  13. package/framework/.claude/skills/new2/CHANGELOG.md +50 -0
  14. package/framework/.claude/skills/new2/SKILL.md +101 -17
  15. package/framework/.claude/skills/prd/CHANGELOG.md +36 -0
  16. package/framework/.claude/skills/prd/SKILL.md +17 -5
  17. package/framework/.claude/skills/prd/assets/state-template.md +8 -1
  18. package/framework/.claude/skills/prd/references/audit-phase.md +13 -1
  19. package/framework/.claude/skills/prd/references/backlog-phase.md +20 -0
  20. package/framework/.claude/skills/prd/references/discovery-phase.md +35 -0
  21. package/framework/.claude/skills/prd/references/ui-design-phase.md +28 -0
  22. package/framework/.claude/skills/prd/references/validation-phase.md +45 -1
  23. package/framework/.claude/skills/worktree-manager/CHANGELOG.md +13 -0
  24. package/framework/.claude/skills/worktree-manager/SKILL.md +11 -1
  25. package/framework/.claude/skills/worktree-manager/scripts/merge-worktree.sh +82 -6
  26. package/framework/.claude/workflows/new-final-review.js +9 -7
  27. package/framework/.claude/workflows/new2-resolve.js +29 -1
  28. package/framework/.claude/workflows/new2.js +153 -17
  29. package/framework/agents/card-schema.md +18 -1
  30. package/framework/agents/research-protocol.md +6 -1
  31. package/framework/scripts/stamp-holistic-audit.js +53 -10
  32. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,92 @@ 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
+ ## [5.6.0] - 2026-07-04
9
+
10
+ **Outcome-integrity wave (FEAT-0068 post-mortem — mayo, 72.78M token, DONE falso).** Il
11
+ batch chiuse 6/6 card + epic come "✅ DONE, merged" mentre il goal dell'epic era invisibile
12
+ sul ~90% delle schermate: il root cause era in `/prd` (inventario ISA sui consumer del
13
+ meccanismo invece che sui proprietari della superficie; recipe ancorata su un componente
14
+ `@deprecated`; due gate phantom-stampati), attraversava card che nessun gate poteva salvare
15
+ (coverage passata vacuamente su un inventario sbagliato), e veniva sigillato da `/new`/`new2`
16
+ (chiusura epic al commit dell'ultima card — PRIMA della final review — con predicato
17
+ conta-figli, nessun verdetto PARTIAL, safety-commit che spazzava file non gated su develop,
18
+ commit agent in detour sul main checkout). 28 finding crit/high confermati adversarialmente;
19
+ ogni fix è ancorato a un'evidenza del run.
20
+
21
+ - **Chiusura epic v2 (`/new` 2.3.0 + `new2` 1.8.0)**: SOLO in merge phase (il gate
22
+ commit-time v4.99.0 è ritirato — aveva anche un anchor bug `^parent:` che lo rendeva
23
+ no-op); predicato esteso (figli **e follow-up** DONE + nessun residual bloccante +
24
+ **AC epic verificati con oracoli**); blocklist JS + guardia post-merge (F-029 twin) +
25
+ ramo **REOPEN** (il ratchet è bidirezionale); classe finding **closure-invalidating**
26
+ (un "goal not achieved" è un difetto di STATO — il fix di prosa non chiude).
27
+ - **Verdetto PARTIAL calcolato** (`final-review.md` + `buildReport`): residual HIGH+ /
28
+ epic aperta / AC epic `[ ]` ⇒ headline `⚠️ PARTIAL` col gap nominato; sezione
29
+ `## Epic goal`; severity sui residui; "nulla perso" mai come surrogato di "non finito".
30
+ - **Igiene git orchestrata**: `merge-worktree.sh --safety-sweep allowlist:` (worktree-manager
31
+ 1.2.0 — il codice non gated va in quarantena etichettata, mai nel trunk sotto un
32
+ "[safety]" opaco); isolamento worktree del commit agent esteso ai TOOL con evidenza
33
+ porcelain + guardia JS (era 7.1M di detour + stash dangling); divieto stash + audit
34
+ post-run dei commit non-card e degli stash del batch (mai "non miei da droppare").
35
+ - **Review**: relay Codex della final review in foreground `--wait` (il polling veniva
36
+ ucciso dall'enforcement structured-output a 83s/600s → fallback freddo da 3.68M);
37
+ esito **refuted** ratificato in `new2-resolve` (premessa falsa = zero edit) + divieto
38
+ di fix che disattivano verifiche mandate da AC (`verification-posture-change`);
39
+ suite aggiunte dalla card ESEGUITE targeted pre-commit (`completeness.md` 1b).
40
+ - **Routing**: `hasMockup` semantico (la card COSTRUISCE la UI mockata — un bare
41
+ `links.design` su card docs va all'owner router; era 6.55M di ui-expert su una card
42
+ docs+ADR).
43
+ - **`/prd` 1.6.0 (il root cause)**: categoria ISA **UI ROLE FAMILY (registry-first)**
44
+ (owner della superficie dal registry + flag BLOCK su `@deprecated`); §0 LOAD CONTRACT
45
+ su `discovery-phase.md` (vista PARTIAL ⇒ offset-Read fino in fondo — la coda persa
46
+ conteneva il Codex completeness cross-check mai eseguito); `module_read` stamps
47
+ ESEGUITI + item 0-ii Phase-evidence audit (2 gate phantom-stampati sul run reale);
48
+ `step_3_mode` enum chiuso + contratto `skipped` (mai design hand-authored fuori
49
+ `/ui-design`) + Reconciliation-lite senza mockup + trigger di ri-enumerazione ISA;
50
+ gate quantificatore-universale sugli AC epic (`invariant_owners:`); stamp holistic
51
+ **evidence-gated** (`stamp-holistic-audit.js --audit-report` → `agents_run`; senza
52
+ artefatto → `status: skipped` = ASSENTE per `/new`); card-writer 1.2.0
53
+ (self-validation eseguita, epic `ac_verification` obbligatoria, mai count hardcodato,
54
+ `links.design` solo su card UI, invariante baseline snapshot); HARD RULE mw-docs
55
+ (+ guardia `/mw` su `kind: docs`); EDIT CONTRACT dello state file (5 retry ciechi
56
+ da ~250k); `research-protocol.md` pre-flight libreria in difesa.
57
+ - **Tooling maintainer**: `new-session-audit.mjs` guadagna **EPIC_AC_UNMET** (FAIL —
58
+ retro-validato: il run FEAT-0068 ora fallisce l'audit invece di passarlo) e
59
+ **GATE_DISABLED_BY_FIX** (WARN) + fix del digest-writer su id workflow con `/`;
60
+ `check-new-parity.mjs` esteso a 21 policy (chiusura epic, PARTIAL, mockup semantico —
61
+ con token FORBIDDEN sui meccanismi ritirati).
62
+ - Deliberatamente rinviati (MED/LOW non verificati dal pass avversariale): digest
63
+ per-batch dei moduli di riferimento (tassa cache ~3-5M), card shape
64
+ VERIFY-ONLY/MECHANICAL-MIGRATION, sampling visivo del goal epic in final review,
65
+ script `update-state.mjs` per `/prd` (mitigato dall'EDIT CONTRACT).
66
+ - Codex parity: **portable** — le policy vivono nei moduli prose SSOT (`/new`, `/prd`)
67
+ e in script zero-dep/shell; i workflow Claude-only (`new2*`, `new-final-review`)
68
+ hanno ricevuto le STESSE policy dei twin prose (guardia di parity estesa a 21 regole).
69
+ Nessuna nuova chiave `baldart.config.yml` → la schema-change propagation rule non si
70
+ applica.
71
+
72
+ ## [5.5.0] - 2026-07-03
73
+
74
+ **Migration deploy chain hardened (FEAT-0067 post-mortem — mayo).** The batch's DB
75
+ migration was fully declared in the cards (`db_migration` + `db_migrations_summary`,
76
+ per the consumer's prd-card-writer overlay) but the remote `db:push` was never
77
+ executed nor surfaced: new2's Migration Gate probed ONLY `migration_plan` (structural
78
+ vocabulary mismatch → silent no-op) and the end-of-batch `db-migration-deploy`
79
+ residual was lost by the mid-run DONE-flip, closing the epic against an unmet DoD.
80
+
81
+ - **Vocabulary aliases** (`/new` 2.2.1, `new2` 1.7.0): the `-auto` delegation gate,
82
+ `/new` Phase 0 1b and new2 Step 3.5 now detect a declared migration under
83
+ `migration_plan.required` (epic) OR `db_migrations_summary` (epic) OR
84
+ `db_migration.required: true` (per-card overlay convention).
85
+ - **new2 Step 5.1b Migration Sync Tail (NEW)**: after the autonomous workflow returns
86
+ (post-merge, on trunk), the SKILL runs the project's post-merge sync check
87
+ (overlay "branch B"); on red it asks Push now / Defer / Override interactively —
88
+ never pushes autonomously. Triggered by the Step-3.5 DECLARATION, not only by the
89
+ residual ledger (belt-and-braces vs a dropped residual). Telemetry
90
+ `migration_sync_tail`.
91
+ - Codex parity: portable (prose-only skill/reference edits; `new2` is Claude-only by
92
+ design — `/new` classic remains the Codex path and gains the same alias probe).
93
+
8
94
  ## [5.4.1] - 2026-07-03
9
95
 
10
96
  **Minimal light lane — the roster for a simple card is now literally: grounding (inline),
package/VERSION CHANGED
@@ -1 +1 @@
1
- 5.4.1
1
+ 5.6.0
@@ -7,6 +7,22 @@ per-item agent merge, the doctor probes, and the discovery hooks — like
7
7
 
8
8
  Formato: [Keep a Changelog](https://keepachangelog.com/) · per-agent SemVer.
9
9
 
10
+ ## [prd-card-writer v1.2.0] — 2026-07-04 (framework v5.6.0 — FEAT-0068 post-mortem)
11
+
12
+ - **Epic AC rules**: mai count di figli hardcodato ("le 6 sub-card"); AC con
13
+ quantificatore universale su una superficie ⇒ `invariant_owners:` dal census
14
+ registry/ISA; `ac_verification` OBBLIGATORIA sull'epic (≥1 oracolo per goal AC —
15
+ consumata dal gate di chiusura epic).
16
+ - **`links.design` FORBIDDEN su card che non costruiscono UI mockata** (docs/test/
17
+ meta-only ⇒ owner coder, riferimenti di contesto in `canonical_docs.additional_refs`)
18
+ — un pointer vagante clampava la build a ui-expert (6.55M su una card docs).
19
+ - **Invariante snapshot-suite**: una card che CREA una suite visual-regression dichiara
20
+ il lifecycle delle baseline (generate+committate in-card, o assertion-based) — pena
21
+ BLOCKER di authoring.
22
+ - **Self-validation**: il writer ESEGUE `validate-card-baseline.js --prd` sul proprio
23
+ output e ritorna solo su exit 0 (token EARS sempre inglesi verbatim) — mai asserire
24
+ "YAML-valid" senza aver eseguito il validator.
25
+
10
26
  ## [prd-card-writer v1.1.0] — 2026-07-03 (framework v5.4.0)
11
27
 
12
28
  - **Proportionality lower-bound** in Card Atomicity Rules: a Tier-Gate TRIVIAL/LIGHT
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: prd-card-writer
3
- version: 1.1.0
3
+ version: 1.2.0
4
4
  description: "Generates atomic backlog cards from an approved PRD. Handles card YAML writing, dependency graph computation, parallel group assignment, and traceability matrices (FR/NFR, ISA, UI). Invoked by the /prd skill at Step 5 to offload the heaviest mechanical phase from the main context. Also runs in Standalone Single-Card Mode to author ONE baseline-conformant follow-up/CHORE/BUG/issue card (no epic+children) — invoked by /new (AC-deferral), new2/new2-resolve, and /issue-review. The canonical card writer: every card-creation path delegates here rather than hand-writing a partial stub."
5
5
  model: opus
6
6
  effort: high
@@ -335,7 +335,18 @@ applies even when N=1.
335
335
  - `business_rationale` (extended — full strategic context)
336
336
  - `scope.summary` + `scope_boundaries` (in_scope summary + out_of_scope deferrals)
337
337
  - `acceptance_criteria` as `[ ] [AC-EPIC-N]` items rolling up the PRD ACs (NOT
338
- duplicating child ACs — track end-to-end outcomes only)
338
+ duplicating child ACs — track end-to-end outcomes only). **v5.6.0 (FEAT-0068)
339
+ epic-AC rules:** (1) NEVER hardcode a child count ("all 6 sub-cards DONE" broke the
340
+ moment follow-ups appeared — write "all child cards **including any added later**");
341
+ (2) an AC with a universal quantifier over a surface ("every screen", "tutte le
342
+ route") MUST list its surface owners in `invariant_owners:` (from the ISA UI ROLE
343
+ FAMILY census) so the closure gate can re-verify them.
344
+ - `ac_verification` — **REQUIRED on the epic (v5.6.0)**: ≥1 executable oracle per
345
+ top-level goal AC (same grounding rule as child cards — only verified commands/greps;
346
+ else `manual:`). The `/new`/`new2` epic-closure gate RUNS these before flipping the
347
+ epic DONE — an epic with no oracle can only close via manual evidence, which is
348
+ slower. (FEAT-0068's goal was greppable at authoring time: "every top-edge family
349
+ member consumes `--safe-area-inset-top`".)
339
350
  - `definition_of_done`: epic-level (e.g. "all sub-card DONE", "PRD test scenarios
340
351
  executed", "ssot-registry entry added")
341
352
  - `execution_strategy` block with `recommended_mode`, `groups[]` (each with
@@ -505,6 +516,14 @@ Every card MUST include ALL fields from the template:
505
516
  `manual: <what a human checks>`. Genuinely undecidable → `[NEEDS CLARIFICATION: …]`.
506
517
  Non-manual oracles SHOULD also appear in `validation_commands` (the validator warns on
507
518
  drift). Consumed by `/new` Phase 2.5, which EXECUTES them.
519
+ - **Snapshot-suite lifecycle invariant (v5.6.0 — FEAT-0068):** a card whose scope CREATES a
520
+ visual-regression / snapshot / screenshot-diff suite MUST declare the baseline lifecycle in
521
+ its requirements + DoD: EITHER "baselines generated (`--update-snapshots` or equivalent) and
522
+ committed IN THIS CARD" (the generate command listed in `validation_commands`/MAY-EDIT
523
+ covering the baseline dir) OR "assertion-based checks with screenshots advisory-only". A
524
+ suite whose baselines "arrive later" with no declared bootstrap is a card-authoring BLOCKER
525
+ — on the real run it detonated as a merge-blocker and the 4.73M repair "fixed" it by
526
+ flag-gating the epic's only visual verification.
508
527
  - `definition_of_done` (checklist including doc invariants). **When `features.has_i18n: true`** AND the
509
528
  card introduces user-facing strings, the DoD MUST carry an i18n-completeness line — NOT merely "strings
510
529
  via `t()` + registered", but: *"new keys authored in the source locale + the i18n context registry (by
@@ -519,7 +538,12 @@ Every card MUST include ALL fields from the template:
519
538
  - `review_profile` (`skip`|`light`|`balanced`|`deep` — computed via Rule C, or honored if pre-set)
520
539
  - `files_likely_touched` (exact paths with NEW/MODIFY)
521
540
  - `links.prd` (path to PRD)
522
- - `links.design` (REQUIRED for any card with UI scope) the card's screen design
541
+ - `links.design` (REQUIRED for any card with UI scope; **FORBIDDEN on cards that build no
542
+ mocked UI — v5.6.0**: a docs/test/meta-only card, or one whose `files_likely_touched` has
543
+ no component/style path, must NOT carry `links.design` even "for context" — downstream the
544
+ `/new` mockup-first router treats it as a build target and clamps the card to `ui-expert`;
545
+ on FEAT-0068 the epic explainer stamped on a docs+ADR card cost 6.55M. Point context-only
546
+ references in `canonical_docs.additional_refs` instead) — the card's screen design
523
547
  reference, resolved to a path **that exists on disk in the worktree**:
524
548
  - **design.html when one was generated** for this screen (Step 3 produced it).
525
549
  - **ELSE the screen's canonical mockup PNG** under `${paths.prd_dir}/<slug>/mockups/`
@@ -732,6 +756,16 @@ The consumer (`new/SKILL.md`) reads `execution_strategy.groups[].level` and
732
756
 
733
757
  ## Output Format
734
758
 
759
+ **Self-validation BEFORE returning (v5.6.0 — you own your domain's deterministic hygiene).**
760
+ Run `node .framework/framework/scripts/validate-card-baseline.js --prd <your card files>` (or
761
+ the `VALIDATOR` path the caller passed) on your own output and fix every deterministic failure
762
+ (enum values, EARS keyword language — the tokens are ALWAYS English verbatim, only the clause
763
+ body follows `identity.language` —, forbidden patterns, missing required fields) IN THIS
764
+ CONTEXT before returning. Return only on exit 0, and state `validator: exit 0 (N cards)` in
765
+ the summary. NEVER assert "YAML-valid / pattern-clean" without having executed the validator —
766
+ on a real session that unexecuted claim cost a full orchestrator round-trip when Step 6
767
+ bounced all 6 children on Italian EARS tokens. Step 6 still re-runs it as the independent gate.
768
+
735
769
  Return to the caller a structured summary:
736
770
 
737
771
  1. **Card list** — IDs and titles of all cards created
@@ -2,6 +2,39 @@
2
2
 
3
3
  Formato: [Keep a Changelog](https://keepachangelog.com/) · [SemVer](https://semver.org/).
4
4
 
5
+ ## 2.3.0 — 2026-07-04 (FEAT-0068 post-mortem: integrità dell'esito)
6
+
7
+ - **Chiusura epic: solo in merge phase, predicato esteso** — `commit.md` c-bis RITIRATO
8
+ (timing: chiudeva PRIMA che la final review potesse smentire il goal; anchor bug:
9
+ `^parent:` non matchava il `parent:` annidato sotto `group:` → gate no-op).
10
+ `merge-cleanup.md` 5e ora richiede: figli **e follow-up** DONE + nessun residual
11
+ bloccante/finding closure-invalidating + **AC epic verificati con evidenza**
12
+ (oracoli `ac_verification`); ramo **REOPEN** per un'epic DONE con scope aperto.
13
+ - **Classe finding "closure-invalidating"** (`final-review.md` F.4): un finding
14
+ "goal/AC epic non raggiunto" è un difetto di STATO — il fix testuale non basta,
15
+ l'epic non chiude (o riapre) nello stesso repair commit.
16
+ - **Verdetto PARTIAL calcolato** (`final-review.md` § Report verdict): residual HIGH+ /
17
+ epic aperta / AC epic `[ ]` ⇒ prima riga `⚠️ PARTIAL` col gap nominato; ✅ riservato.
18
+ - **Routing mockup semantico** (`implement.md` 6a): `HAS_MOCKUP` = la card COSTRUISCE
19
+ la UI mockata (design_src, o design + bindings/file UI) — un bare `links.design` su
20
+ card docs/meta va all'owner router (era: clamp a ui-expert, 6.55M su una card docs).
21
+ - **Stamp holistic evidence-gated** (`implement.md` step 4 P1): uno stamp senza
22
+ `agents_run` non vuoto = ASSENTE → il plan-auditor gira (phantom stamp FEAT-0068).
23
+ - **Suite aggiunte dalla card: eseguite, non solo parse** (`completeness.md` 1b): uno
24
+ spec ADDED va RUN targeted pre-commit; suite snapshot senza lifecycle baseline
25
+ dichiarato = `Partial` → gap-fix subito (era: merge-blocker + repair da 4.73M che
26
+ flag-gatava la verifica dell'epic).
27
+
28
+ ## 2.2.1 — 2026-07-03 (FEAT-0067 post-mortem: migration vocabulary aliases)
29
+
30
+ - Il gate di delega `-auto` (condizione 4) e il Migration Gate Phase 0 1b (setup.md
31
+ step 2) ora rilevano una migrazione dichiarata sotto QUALSIASI vocabolario:
32
+ `migration_plan.required` (epic), `db_migrations_summary` (epic),
33
+ `db_migration.required: true` (per-card, convenzione overlay consumer). Una
34
+ migrazione dichiarata solo via alias con artifact non ancora su disco degrada come
35
+ oggi (missing-artifact) ma la dichiarazione viene SEMPRE registrata nel tracker —
36
+ il sync post-merge e il ledger dei follow-up devono conoscerla.
37
+
5
38
  ## 2.2.0 — 2026-07-03 (framework v5.4.1)
6
39
 
7
40
  - **Minimal light lane — roster cut to the core four.** A single light card now runs:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: new
3
3
  effort: medium
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  description: >
6
6
  Orchestrate a team of specialized agents to implement one or more backlog cards
7
7
  end-to-end inside a dedicated worktree, with code review, doc review, QA, and
@@ -66,10 +66,16 @@ kickoff, right after arg parsing):
66
66
  2. `FORCE_INLINE == false` (the user did not pass `-inline`).
67
67
  3. The `Workflow` tool is available in this session AND `.claude/workflows/new2.js`
68
68
  is linked AND the `new2` skill is available.
69
- 4. No epic card in the batch declares `migration_plan.required: true` (cheap YAML
70
- probe on the batch's `group.parent` epics). A declared migration keeps the
71
- classic path its Phase 0 step 1b owns the owner-gated apply under
72
- § "AUTONOMOUS RESOLUTION RULE"; `new2`'s own migration gate is interactive.
69
+ 4. No card in the batch declares a DB migration, under ANY of the recognized
70
+ vocabularies (cheap YAML probe): epic `migration_plan.required: true`, epic
71
+ `db_migrations_summary` (non-empty), or a batch card with
72
+ `db_migration.required: true` (the consumer-overlay convention e.g. mayo's
73
+ prd-card-writer overlay). A declared migration keeps the classic path — its
74
+ Phase 0 step 1b owns the owner-gated apply under § "AUTONOMOUS RESOLUTION
75
+ RULE"; `new2`'s own migration gate is interactive. *Why the aliases are
76
+ load-bearing*: probing only `migration_plan` silently classified a
77
+ `db_migration`-declaring batch as migration-free (FEAT-0067 post-mortem — the
78
+ remote `db:push` was never surfaced).
73
79
 
74
80
  **Action**: log ONE tracker line `[DELEGATED] -auto batch → new2 engine
75
81
  (off-context): <residual args>` and invoke the `new2` skill with the SAME residual
@@ -33,14 +33,18 @@
33
33
  a. Edit the backlog YAML (`${paths.backlog_dir}/<CARD-ID>.yml`): set `status: DONE`, add `completed_date: <today>`, and add `provenance.implementation_session: <SESSION-ID>` (this run's session UUID — get it with `Bash(echo "${CLAUDE_CODE_SESSION_ID:-}")`; if empty, omit the field). Merge into any existing `provenance:` block written by `/prd` — do NOT overwrite `planning_session`. This makes an implementation bug traceable back to the session that produced it (`~/.claude/projects/*/<id>.jsonl`).
34
34
  b. Add implementation notes summarizing what was built.
35
35
  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.
36
- c-bis. **Epic-closure gate (deterministic since v4.99.0)**: if the card YAML declares a parent epic (`parent:` field), check AFTER step a set this card DONE — whether it was the LAST open child. Deterministic count, no judgement:
37
- ```bash
38
- PARENT=$(awk '/^parent:/ {print $2; exit}' ${paths.backlog_dir}/<CARD-ID>.yml)
39
- if [ -n "$PARENT" ]; then
40
- PENDING=$(grep -l "^parent: ${PARENT}" ${paths.backlog_dir}/*.yml | xargs grep -L "^status: DONE" | wc -l)
41
- fi
42
- ```
43
- When `PENDING` is `0`: flip the PARENT epic's status in its ssot-registry.md entry to DONE **in the SAME commit**, and if the parent epic has its own backlog YAML, set its `status: DONE` + `completed_date` too. Non-triggers (do nothing, idempotent): the card has no `parent:`; siblings still pending (`PENDING > 0`); the parent entry is already DONE. This closes a recurring consumer gap: step 28c alone updates the CARD's feature-area entry, so epics stayed `IN_PROGRESS` after their last child closed and were only caught by the nightly doc routine (3 confirmed occurrences across two audit windows).
36
+ c-bis. **Epic closure does NOT happen here (v5.6.0 — the v4.99.0 commit-time gate is RETIRED).**
37
+ Two proven defects (FEAT-0068 post-mortem): (1) **timing** — closing at the last card's
38
+ commit runs structurally BEFORE the final review can disprove the epic goal (the FEAT-0068
39
+ epic closed DONE 13 minutes before the review proved the goal unmet on ~90% of screens),
40
+ and the commit context cannot see follow-up cards materialized later in the batch;
41
+ (2) **anchor bug** — the retired gate grepped `^parent:` but the card schema nests
42
+ `parent:` indented under `group:`, so it was a silent no-op on schema-conformant cards.
43
+ Epic closure now lives ONLY in the merge phase (`merge-cleanup.md` Phase 6b step 5e,
44
+ extended predicate: children **and follow-ups** DONE + no blocking residual + **epic ACs
45
+ verified**), which runs AFTER the final review. At commit time the parent epic and every
46
+ sibling card YAML are READ-ONLY. The epic-staleness safety net the v4.99.0 gate closed
47
+ stays closed by Phase 6b 5e + the nightly doc routine.
44
48
  d. **Verify the write**: re-read the YAML file and confirm `status: DONE` is present. If not, retry the edit.
45
49
  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.
46
50
  29. **Update tracker**: move card to `## Completed Cards` with commit hash(es), summary, flags, **and `card_status: DONE (verified)`** — the tracker is the only state surface (§ "State surface — the tracker only"); do not also emit a TaskUpdate or Progress-Bar turn for the transition. If you surface the card completion to the user at all, do it as a short prose line folded into the commit turn, never a dedicated turn.
@@ -36,6 +36,16 @@ Before triggering any review, you MUST verify that the coder agent implemented *
36
36
  `conditional_items` section → flag as `Missing` (the coder must document the branch taken).
37
37
 
38
38
  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.
39
+ 1b. **Card-added test suites must RUN, not just parse (v5.6.0 — FEAT-0068).** If the card's diff
40
+ ADDS or modifies a test/spec file, the completeness evidence for that item is a targeted
41
+ EXECUTION of exactly that file (`npx vitest run <file>` / `npx playwright test <file>` / the
42
+ toolchain equivalent), in the worktree, before commit — a `--list`/parse check only proves the
43
+ file compiles, not that the suite can pass. A suite that cannot run yet by design (e.g. a
44
+ visual-regression suite whose baselines are generated later) is only `Done` if the card
45
+ EXPLICITLY declares that lifecycle (see `card-schema.md` § snapshot-suite invariant) AND the
46
+ declared bootstrap command is exercised; otherwise classify `Partial` and route to the
47
+ gap-fix loop NOW — the FEAT-0068 card shipped a baseline-less suite that detonated as a
48
+ merge-blocker and was "fixed" by flag-gating the epic's only visual verification (4.73M).
39
49
  2. Re-read the backlog card (`requirements`, `acceptance_criteria`, `unknowns`, and `definition_of_done` fields).
40
50
  3. Build a checklist — one row per item:
41
51
 
@@ -334,6 +334,16 @@ that is a **gate violation**: log it as
334
334
  - **Each domain specialist OWNS its lane end-to-end** — it runs its OWN false-positive check in the finding pass (doc-reviewer for doc, api-perf-cost-auditor for api/perf/data, and the Codex/`code-reviewer`-fallback engine for code), so its surviving findings are **already validated**. Do **NOT** cross-validate a doc or api finding by spawning `code-reviewer` (that is the WRONG specialist judging another domain), and do **NOT** re-run the same specialist over its own findings (self-judge — no model diversity). Codex findings are likewise already FP-validated (Step F.3 protocol includes it).
335
335
  - **Residual only:** a finding the originating specialist explicitly leaves UNRESOLVED (`confidence < 80`) is routed to the finding's **domain specialist** (by `domain`: doc→doc-reviewer, api/perf→api-perf-cost-auditor, security/migration→security-reviewer, test→qa-sentinel, else code-reviewer) over the cited file:line. If that domain specialist **is** the originating finder (it already had its pass), classify `NEEDS_MANUAL_CONFIRMATION` instead of re-spawning it — never self-judge, never silently drop.
336
336
  - Classify: `VERIFIED` | `FALSE_POSITIVE` | `NEEDS_MANUAL_CONFIRMATION`.
337
+ - **Closure-invalidating findings (v5.6.0 — FEAT-0068 post-mortem).** A VERIFIED finding (any
338
+ severity) asserting that an **epic goal or epic AC is NOT met** while state says otherwise —
339
+ overclaim in the SSOT/registry, "DONE but unmet", "goal not achieved" — is a **STATE defect,
340
+ not a prose defect**. Tag it `closure_invalidating: true`. Its fix has TWO mandatory parts:
341
+ (1) the text correction (the doc fixer's job as usual), AND (2) the **state reversal** — the
342
+ named epic must NOT be closed in Phase 6b, or, if already `DONE` on disk, must be REOPENED to
343
+ `IN_PROGRESS` in the same repair commit (`merge-cleanup.md` 5e step a). Accepting the text
344
+ fix alone as resolution merges a registry that says "goal not achieved" alongside an epic
345
+ YAML that says DONE — the exact FEAT-0068 contradiction. The batch verdict becomes PARTIAL
346
+ (§ Report verdict below) whenever one of these stands.
337
347
  - `VERIFIED` findings proceed to fixes — **EXCEPT no-action ones** (`requires_action:false`, or a "no fix required" / "acceptable as-is" / "verified non-issue" direction; MEDIUM/LOW only). A no-action finding is TRUE but needs no change: record it (`decision=skipped | reason=no-action`) and do NOT route it to a writer. (The delegated `new-final-review` workflow returns these separately as `noActionFindings` + `summary.noAction`; the inline path classifies them here.) **`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. **When AUTONOMOUS, apply § "AUTONOMOUS RESOLUTION RULE" (SKILL.md): category=blocker; recommended=treat NEEDS_MANUAL_CONFIRMATION as VERIFIED (never as a false positive), else materialize a follow-up card.** Only `FALSE_POSITIVE` are dropped.
338
348
 
339
349
  ### Step F.5 — Apply fixes and final build
@@ -403,6 +413,19 @@ that is a **gate violation**: log it as
403
413
  4. Emit the **minimal end-of-batch result block** (per § "orchestrator is near-silent" in the core SKILL.md — this is NOT a per-phase report). ONE line per card and nothing more of the process telemetry:
404
414
  - `<CARD-ID>: merged @<sha> | failed: <one clause> | deferred → <followup-id>`
405
415
 
416
+ **Report verdict (v5.6.0 — HARD headline rule, FEAT-0068 post-mortem).** The FIRST line of the
417
+ result block is a verdict, and it is computed, not felt:
418
+ - `⚠️ PARTIAL — obiettivo epic NON raggiunto: <one clause naming the gap>` whenever ANY of:
419
+ a HIGH/BLOCKER residual or follow-up carrying substantive scope work exists; the parent epic
420
+ was left open (or reopened) by Phase 6b 5e; a closure-invalidating finding stands; any epic
421
+ AC is still `[ ]`. Name the gap and its follow-up card in the first three lines.
422
+ - `✅ COMPLETO` is RESERVED for: every card merged, no HIGH+ residual, epic (when present)
423
+ closed with ACs verified.
424
+ A run that ships 6/6 cards but leaves the epic goal on 10% of its surface is PARTIAL — the
425
+ FEAT-0068 report headlined "✅ batch completo" over a disclosed-but-buried HIGH gap, and the
426
+ user discovered it only by asking. "Nulla perso" (tracking) is never a substitute for "non
427
+ finito" (truth): a follow-up that holds the epic's remaining work is REMAINING WORK.
428
+
406
429
  Then, **only if non-empty**, the **actionable residue**: issues needing user attention (anything unresolved, partially wired, or flagged — terse, with `path:line` / `CARD-ID` exact). All process telemetry — files changed, test/build/lint status, fix cycles, review-finding counts, UX/QA verdicts, commit + merge hashes, card-status reconciliation, worktree cleanup, knowledge-corpus sync — is **NOT rendered**: it lives in the tracker and `$METRICS/skill-runs.jsonl`. (The Next Steps & Launch Command in 4b below and any Production Readiness manual steps ARE part of the actionable residue — keep them.)
407
430
 
408
431
  4b. **Next Steps & Launch Command** (MANDATORY section — always present):
@@ -11,10 +11,10 @@
11
11
  2b. **Claim** — only now set the card status to `IN_PROGRESS` (in the backlog YAML / tracker) and assign yourself. This is a state write, not a visibility emission — do not also spend a TaskUpdate / Progress-Bar turn (§ "State surface — the tracker only").
12
12
  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.
13
13
  2d. **Light-lane inline grounding (since v5.4.0 — BLOCKING gate for steps 3–4, after 2c)** — when the card is NOT provisionally trivial AND `review_profile == light`: **SKIP step 3 (the dedicated codebase-architect spawn) and step 4** — the OWNER agent grounds INLINE instead, per **AGENTS.md § Change Tiers, orchestrated-pipeline exception** (a light card is ≤3 files with no logic-risk signal by Rule C; a dedicated retriever at that scale costs more than the exploration it isolates). The understanding obligation is UNCHANGED — only the delegation is waived: the owner briefing (step 6/7) MUST carry the line "Ground INLINE before coding: read the files in scope + their immediate integration points; scoped exploration only". Step 3a still runs (write Active Code Context from the card YAML, noting `grounding: inline-light`). Log `phase1: INLINE-LIGHT (review_profile=light — no retriever spawn, owner grounds inline)`. `balanced`/`deep` cards run steps 3, 3a, 4 as written — this lane never applies to them.
14
- 3. **(skip when provisionally trivial — see 2c — or on the light lane — see 2d)** 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`. Likewise, when `features.has_code_graph: true`, the architect uses the Graphify code graph for structural/relational lookups (ambient flag) per `agents/code-graph-protocol.md`. The orchestrator does NOT propagate either 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.) **Pass `OUTPUT=terse` in the architect prompt (since v4.49.0)** — this is grounding for the coder/reviewer, not an explanation, so the architect returns its structured contract (reuse table + canonical evidence + `path:line — symbol` rows + `totals:`) without narrative prose. **Pass the analysis profile too (since v4.94.0)**: `PROFILE=ui` when the card has a non-empty `links.design` OR `links.design_src` (the same mockup bit that drives step 6a), else `PROFILE=feature` — contract and per-profile scoping in `agents/analysis-profiles.md` (its § 3 caller routing table is normative). The profile is deterministic from the card YAML; never leave the architect to infer it. The verbatim baseline persisted at step 5b keeps all the substance a lean `/codexreview` needs (paths, signatures, patterns, high-risk paths) while staying small in the orchestrator's context and on disk. **Baseline content contract (MANDATORY — since v4.56.0):** the architect prompt is grounding INPUT only — pass the card scope, `files_likely_touched`, and the question to map. NEVER put line-level fix directives ("remove lines 90-91", "Fix: use X"), the words "implement/fix/apply", or acceptance-criteria framed as a task into the architect prompt. The architect produces a read-only MAP (file/symbol locations, patterns, type signatures, integration points, high-risk paths); it does NOT implement and has no `Task`/Agent tool to delegate (see `codebase-architect.md` § Role boundary). The coder is a separate spawn the orchestrator owns.
14
+ 3. **(skip when provisionally trivial — see 2c — or on the light lane — see 2d)** 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`. Likewise, when `features.has_code_graph: true`, the architect uses the Graphify code graph for structural/relational lookups (ambient flag) per `agents/code-graph-protocol.md`. The orchestrator does NOT propagate either 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.) **Pass `OUTPUT=terse` in the architect prompt (since v4.49.0)** — this is grounding for the coder/reviewer, not an explanation, so the architect returns its structured contract (reuse table + canonical evidence + `path:line — symbol` rows + `totals:`) without narrative prose. **Pass the analysis profile too (since v4.94.0)**: `PROFILE=ui` when the card's `HAS_MOCKUP` bit is true (the same semantic mockup test that drives step 6a — v5.6.0: a bare `links.design` pointer on a docs/meta card does NOT make it a UI card), else `PROFILE=feature` — contract and per-profile scoping in `agents/analysis-profiles.md` (its § 3 caller routing table is normative). The profile is deterministic from the card YAML; never leave the architect to infer it. The verbatim baseline persisted at step 5b keeps all the substance a lean `/codexreview` needs (paths, signatures, patterns, high-risk paths) while staying small in the orchestrator's context and on disk. **Baseline content contract (MANDATORY — since v4.56.0):** the architect prompt is grounding INPUT only — pass the card scope, `files_likely_touched`, and the question to map. NEVER put line-level fix directives ("remove lines 90-91", "Fix: use X"), the words "implement/fix/apply", or acceptance-criteria framed as a task into the architect prompt. The architect produces a read-only MAP (file/symbol locations, patterns, type signatures, integration points, high-risk paths); it does NOT implement and has no `Task`/Agent tool to delegate (see `codebase-architect.md` § Role boundary). The coder is a separate spawn the orchestrator owns.
15
15
  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.
16
16
  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. **This skip is the NORMAL path for a card implemented right after `/prd`, not an occasional optimization** — `/prd` now guarantees the `metadata.holistic_audit` stamp lands on every audited card (deterministic backstop at `validation-phase.md` Step 7 item 5b, since the v4.88.2 provenance-reliability fix), so P1 below holds whenever the batch is freshly authored. Skip the plan-auditor when **BOTH** hold:
17
- - **P1 — provenance present**: the card has `metadata.holistic_audit` with non-empty `audited_at`, `audited_commit`, `audited_set`.
17
+ - **P1 — provenance present AND evidence-backed (v5.6.0)**: the card has `metadata.holistic_audit` with non-empty `audited_at`, `audited_commit`, `audited_set`, **and a non-empty `agents_run` list** (the v5.6.0 evidence field the stamper writes only when it received a real audit report). A stamp with `status: skipped` or WITHOUT `agents_run` is treated as **ABSENT** — the FEAT-0068 `/prd` session stamped all 6 cards while the Step 6.2–6.6 audit team never spawned (phantom stamp), and P1∧P2 would have suppressed the plan-auditor on a false premise. Pre-v5.6.0 stamps (no `agents_run` field at all) therefore fall through to RUN the plan-auditor — deliberate fail-safe, not a bug.
18
18
  - **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`):
19
19
  ```bash
20
20
  # empty AC, AC not in history, or any git error → treat as drift (do NOT skip)
@@ -57,7 +57,17 @@
57
57
  If card is an epic (id ends "-00" OR filename ends "-epic.yml" OR review_profile == "skip"
58
58
  with no requirements): SKIP — log "[ROUTER] card <ID> is an epic (tracker) — skipped,
59
59
  not implemented" and move to the next card.
60
- If card has links.design OR links.design_src (a mockup exists):
60
+ # v5.6.0 (FEAT-0068): "has a mockup" is SEMANTIC, not a bare-field test. The /prd epic
61
+ # explainer html stamped on 5/6 cards clamped a docs+ADR card to ui-expert (6.55M, the
62
+ # run's costliest agent) and put a meta-only card through the fidelity lane.
63
+ HAS_MOCKUP := links.design_src is non-empty
64
+ OR ( links.design is non-empty
65
+ AND ( component_bindings is non-empty
66
+ OR files_likely_touched intersects component/style/UI source paths ) )
67
+ # A bare links.design on a docs/test/meta-only card is a POINTER to the epic's design
68
+ # explainer, not a build target → route by owner_agent (step 6b). Log the demotion:
69
+ # "[ROUTER] card <ID> carries links.design but builds no mocked UI → owner_agent router".
70
+ If HAS_MOCKUP:
61
71
  IF the /ui-implement skill is available:
62
72
  DELEGATE this card's mockup→code implement + fidelity verify to /ui-implement
63
73
  in programmatic mode (contract: ui-implement/references/integration.md).
@@ -82,7 +92,7 @@
82
92
  ```
83
93
 
84
94
  `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.
85
- 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:
95
+ 6b. **Agent dispatch (router — cards WITHOUT a mockup only).** Reached only when step 6a did not fire (`HAS_MOCKUP` false no mockup, or a bare `links.design` pointer on a card that builds no mocked UI). Read `owner_agent` from the card YAML and resolve the spawn target per the table in § Agent Routing above:
86
96
 
87
97
  ```
88
98
  Let raw = card.owner_agent (string, may be missing).
@@ -93,24 +93,45 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
93
93
 
94
94
  For each **distinct parent epic** referenced by the batch — the set of `group.parent`
95
95
  values across the batch cards, PLUS any card in the batch that is itself an epic
96
- (`group.is_epic: true`) — do:
97
- a. Read the epic parent card `${paths.backlog_dir}/<EPIC-ID>.yml`. If `status: DONE`
98
- already skip (idempotent).
99
- b. Check that **every** child is DONE (not just the batch's subset children
100
- implemented in earlier sessions count too):
96
+ (`group.is_epic: true`) — close ONLY when the FULL predicate (a)–(d) holds
97
+ (v5.6.0, FEAT-0068 post-mortem: the old children-count-only predicate closed an epic whose
98
+ goal was unmet on ~90% of screens — the count was true and the DoD was false):
99
+ a. Read the epic parent card `${paths.backlog_dir}/<EPIC-ID>.yml`.
100
+ - `status: DONE` already **and** the checks below still hold → skip (idempotent).
101
+ - `status: DONE` already **but** (b)/(c)/(d) now FAIL (an open follow-up child appeared, a
102
+ closure-invalidating finding stands) → **REOPEN** it: set `status: IN_PROGRESS`, annotate
103
+ `completed_date`, add note `"REOPENED — closed against open scope (v5.6.0 guard)"`, fold
104
+ into the reconciliation commit. The ratchet is two-way: a false DONE never survives a
105
+ reconciliation pass.
106
+ b. Check that **every** child is DONE (not just the batch's subset — children implemented in
107
+ earlier sessions count too, and **follow-up cards count as children**: a
108
+ `<card>-followup-*.yml` carrying `parent: <EPIC-ID>` is an OPEN child until implemented):
101
109
  ```bash
102
110
  # Lists children of <EPIC-ID> that are NOT yet DONE. Empty output ⇒ all DONE.
111
+ # No ^ anchor — the schema nests `parent:` indented under `group:` (the v4.99.0
112
+ # commit-time gate anchored it and was a silent no-op; do not re-introduce that).
103
113
  grep -l "parent: <EPIC-ID>" ${paths.backlog_dir}/*.yml | xargs grep -L "status: DONE"
104
114
  ```
105
- c. **Only if** that command prints nothing (all children DONE) force-update the epic
106
- parent: set `status: DONE`, add `completed_date: <today>`, add note
107
- `"Marked DONE by epic-closure gate (Phase 6b) all children DONE"`. Stage it and
108
- **fold into the SAME reconciliation commit** as step 5 (or, if step 5 didn't run
109
- because all children were already DONE, make a dedicated
110
- `[BATCH] Close epic <EPIC-ID> all children DONE` commit, honoring the same
111
- COMMIT_LOCK / doc-freshness precautions as step 5a–5d).
112
- d. **If any child is still open** leave the epic untouched: it is genuinely still in
113
- progress, and step-4b's "Card rimanenti nell'epic" table already reports the gap.
115
+ c. **No blocking open work attached to the epic**: scan the tracker's `## Issues & Flags` +
116
+ residual/follow-up ledger for this batch — any open `scope-expansion` / `unresolved` /
117
+ `ac-unmet` item on a child of this epic, or any **closure-invalidating** final-review
118
+ finding (`final-review.md` § Closure-invalidating findings) naming this epic's goal
119
+ leave the epic OPEN (a text fix to the overclaiming doc does NOT clear this).
120
+ d. **Epic ACs verified**: read the epic YAML's own `acceptance_criteria`. For each `[ ]`
121
+ item, verify it with concrete evidence — run its `ac_verification` oracle when present,
122
+ else a targeted check and flip to `[x]` ONLY with evidence recorded in the tracker. An
123
+ AC you cannot verify stays `[ ]` and the epic stays OPEN (report which AC and why).
124
+ Never close an epic whose own checklist still has `[ ]` items.
125
+ e. **Only if (b)+(c)+(d) all pass** → update the epic parent: set `status: DONE`, add
126
+ `completed_date: <today>`, add note `"Marked DONE by epic-closure gate (Phase 6b) —
127
+ children+follow-ups DONE, ACs verified"`. Stage it and **fold into the SAME reconciliation
128
+ commit** as step 5 (or, if step 5 didn't run because all children were already DONE, make a
129
+ dedicated `[BATCH] Close epic <EPIC-ID>` commit, honoring the same COMMIT_LOCK /
130
+ doc-freshness precautions as step 5a–5d).
131
+ f. **If any check fails** → leave the epic untouched (or REOPEN per step a) and report the
132
+ concrete reason: step-4b's "Card rimanenti nell'epic" table + the final report's epic-goal
133
+ line must show it — the batch verdict is **PARTIAL**, never ✅, while the epic is open
134
+ (`final-review.md` § Report verdict).
114
135
  6. **Update tracker** with reconciliation results:
115
136
  ```
116
137
  ## Phase 6b — Status Reconciliation
@@ -22,7 +22,7 @@
22
22
  1b. **Migration Gate (BLOCKING only when a migration is *declared* — else a silent no-op)** — resolve DB migrations interactively **before** the worktree exists, so the schema is live before any card builds against it. *Why this exists*: a migration applied to a shared/remote DB is owner-gated, so without this gate it is deferred to the END of the batch — and every downstream card in the batch is then built and verified against a schema that is not yet live (`validation_commands` / QA / E2E / DB-generated `tsc` types fail falsely → those cards cascade into deferral/blocked). Front-loading the migration removes that root cause. **The declaration lives in the EPIC card** (`migration_plan` block — project-specific, authored by the user, typically via the `.baldart/overlays/new.md` overlay). Steps:
23
23
 
24
24
  1. **Find the batch's epic card(s).** Collect the distinct `group.parent` of the batch cards (or, for a `-full` invocation, the parent already known). For each, locate the epic YAML in `${paths.backlog_dir}` (filename `<PARENT>-*-epic.yml`, or the card whose `id == <PARENT>` / `group.is_epic: true`) and Read it.
25
- 2. **Look for `migration_plan` with `required: true`.** If **no** epic in the batch declares one → write `## Migration\nnone (no migration_plan declared)` to the tracker and **proceed to step 2** (behaviour is identical to today — zero extra prompts). This is the common case; do not surface anything.
25
+ 2. **Look for a declared migration — under ANY recognized vocabulary.** Primary: epic `migration_plan` with `required: true`. **Compat aliases (consumer-overlay conventions — same semantics, different field names)**: epic `db_migrations_summary` (non-empty), or any batch card carrying `db_migration.required: true` (map: `artifacts` ← each `db_migration.expected_file`; `summary` ← the slug; apply/push modalities ← `db_migration.remote_push` + the overlay's post-merge section; no `verify` unless declared). A migration declared ONLY via alias whose `expected_file` does not yet exist on disk (it will be authored mid-run by the coder) follows the step-3 missing-artifact degradation — but the declaration itself MUST still be recorded in the tracker (`## Migration\ndeclared (via db_migration) — deferred to post-merge sync`) so the post-merge Migration Sync step and the follow-up ledger know about it. If **nothing** declares a migration → write `## Migration\nnone (no migration declared)` to the tracker and **proceed to step 2** (behaviour is identical to today — zero extra prompts). This is the common case; do not surface anything.
26
26
  3. **(declared) Verify the artifacts exist on disk.** For each path in `migration_plan.artifacts`, check it exists under `$MAIN`. If **any is missing** → do **NOT** apply or prompt; write `## Migration\ndeclared but artifact(s) missing: <paths> — degraded to deferred (author the migration first)` to the tracker and **proceed to step 2** (the migration falls back to the current end-of-batch owner-gated deferral — no regression). *(Auto-generating a missing artifact is out of scope; the migration must already be authored to be applied up-front.)*
27
27
  4. **(declared + artifacts present) Assemble the apply modalities**, in this source order, de-duplicating by `id`: (a) `migration_plan.apply_modalities` from the epic block; (b) a `## Migration modalities` section in `.baldart/overlays/new.md` if present; (c) any project-memory note on how this project applies migrations; (d) the built-in tail `["Già applicata — prosegui", "Abort"]`. Each modality is `{ id, label, command? }`.
28
28
  5. **`AskUserQuestion`** — `"La epic dichiara una migrazione DB (<summary>). Va applicata PRIMA del batch così le card downstream verificano contro lo schema reale. Come procedo?"` with up to 4 of the assembled modalities (always include "Già applicata — prosegui" and "Abort" as the last options). This is a legitimate Phase 0 question (Auto Mode does not override it).
@@ -2,6 +2,56 @@
2
2
 
3
3
  Formato: [Keep a Changelog](https://keepachangelog.com/) · [SemVer](https://semver.org/).
4
4
 
5
+ ## 1.8.0 — 2026-07-04 (FEAT-0068 post-mortem: integrità dell'esito + igiene git)
6
+
7
+ - **`new2.js`**: step 4b (chiusura epic) RIMOSSO dal commit agent — la chiusura vive
8
+ SOLO nella merge phase 5e col predicato v5.6.0 (blocklist JS `closureBlockedEpics`
9
+ da residual/follow-up/finding closure-invalidating + figli/follow-up DONE + AC epic
10
+ verificati, `epicsLeftOpen` con motivi); **guardia post-merge** gemella di F-029
11
+ (`epic-closure-guard` VIOLATION + residual `false-epic-closure` HIGH → la skill
12
+ riapre); detection **closure-invalidating** sui finding della final review.
13
+ - **`buildReport`**: verdetto calcolato `⚠️ PARTIAL`/`✅ COMPLETO` come PRIMA sezione,
14
+ sezione `## Epic goal` per-epic, `severity` sui residui (`residualSeverity`),
15
+ "nulla perso" consentito solo senza HIGH.
16
+ - **Commit agent**: clausola WORKTREE ISOLATION estesa ai TOOL (Read/Edit/Write path
17
+ assoluti — il cwd HARD RULE v5.3.0 copriva solo Bash), path del card YAML del
18
+ worktree passato esplicito, sibling/epic READ-ONLY, evidenza porcelain
19
+ before/after sul main + **isolation-guard JS** (main sporcato = VIOLATION +
20
+ residual HIGH). Era: 79 turni/4.30M di detour + stash dangling.
21
+ - **Merge**: `merge-worktree.sh --safety-sweep allowlist:` (solo bookkeeping del
22
+ batch; codice non gated mai spazzato nel trunk — F-030 per costruzione); divieto
23
+ esplicito di `git stash` ovunque (ff-pull bloccato = leave+report).
24
+ - **`new2-resolve.js`**: esito **`refuted`** ratificato avversarialmente (premessa
25
+ falsa = zero edit — era: 4.73M per "fixare" un blocker falso disattivando la suite
26
+ visual-regression) + `terminalReason: verification-posture-change` (un fix che
27
+ skippa/flag-gata una verifica mandata da un AC è FORBIDDEN).
28
+ - **`new-final-review.js`**: relay Codex in **foreground `--wait`** (una sola Bash,
29
+ timeout 600000) — l'enforcement structured-output forzava un TIMEOUT a 83s/600s e
30
+ il processo moriva col relay → fallback freddo da 3.68M; reap dell'orfano scoped
31
+ al worktree su timeout reale.
32
+ - **Routing**: `hasMockup` semantico nel cardGraph (BUILDS the mocked UI) +
33
+ `parentEpic` per blocklist/report.
34
+ - **SKILL.md**: Step 2 predicato di chiusura completo + **ramo REOPEN** (ratchet
35
+ bidirezionale); Step 4 presenta il verdetto verbatim (mai ri-headline un PARTIAL);
36
+ **Step 4b audit igiene git** (commit non-card ispezionati con `git show --stat` —
37
+ mai attribuire provenienza senza check; stash del batch riconciliati, mai "non
38
+ miei"; residual `main-repo-contamination` ripristinati); pre-sha del trunk
39
+ registrato al kickoff.
40
+
41
+ ## 1.7.0 — 2026-07-03 (FEAT-0067 post-mortem: migration mai deployata)
42
+
43
+ - **Step 3.5 vocabulary aliases**: il Migration Gate ora riconosce, oltre a
44
+ `migration_plan.required` (epic), anche `db_migrations_summary` (epic) e
45
+ `db_migration.required: true` (per-card — convenzione overlay consumer, es. mayo).
46
+ Root cause FEAT-0067: il probe solo-`migration_plan` classificava la batch come
47
+ migration-free → gate in silent no-op, `db:push` mai emerso.
48
+ - **Step 5.1b Migration Sync Tail (NEW)**: post-merge, il ramo B interattivo del sync
49
+ gate eseguito dalla SKILL (check-sync read-only → su rosso `AskUserQuestion`
50
+ Push now / Defer / Override; mai push in autonomo). Trigger belt-and-braces sulla
51
+ DICHIARAZIONE Step 3.5, non solo sul residual ledger (che il DONE-flip di FEAT-0067
52
+ aveva perso). Telemetria `migration_sync_tail`.
53
+ - Step 1.5: nota di delega aggiornata (il probe di `/new -auto` copre tutti i vocabolari).
54
+
5
55
  ## (workflow new2.js, framework v5.4.1) — 2026-07-03
6
56
 
7
57
  - Minimal light lane mirror: single-card light adds per-card doc-reviewer to the review