baldart 4.11.0 → 4.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/VERSION +1 -1
- package/framework/.claude/agents/coder.md +3 -3
- package/framework/.claude/skills/new/SKILL.md +185 -2351
- package/framework/.claude/skills/new/references/codex-gate.md +129 -0
- package/framework/.claude/skills/new/references/commit.md +57 -0
- package/framework/.claude/skills/new/references/completeness.md +284 -0
- package/framework/.claude/skills/new/references/final-review.md +267 -0
- package/framework/.claude/skills/new/references/implement.md +353 -0
- package/framework/.claude/skills/new/references/merge-cleanup.md +175 -0
- package/framework/.claude/skills/new/references/metrics.md +72 -0
- package/framework/.claude/skills/new/references/production-readiness.md +232 -0
- package/framework/.claude/skills/new/references/review-cycle.md +247 -0
- package/framework/.claude/skills/new/references/setup.md +249 -0
- package/framework/.claude/skills/new/references/team-mode.md +253 -0
- package/framework/.claude/skills/worktree-manager/SKILL.md +16 -8
- package/framework/agents/coding-standards.md +5 -5
- package/package.json +1 -1
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<!-- Modulo on-demand di /new — NON un file installato a sé. Caricato via Read dalla § "Routing" del SKILL.md core. -->
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
### Phase 2.55 — Simplify (code cleanup before review)
|
|
6
|
+
|
|
7
|
+
> **Trivial fast-lane gate**: re-confirm `IS_TRIVIAL` on the ACTUAL committed diff (§ "Trivial-card fast-lane" — all 3 conditions, now including the real non-source diff check). If trivial → **SKIP this phase** AND Phase 3.5 QA + Phase 3.7 Codex; instead run the **inline mechanical gates** (`markdownlint` on changed `.md`, `lint` on lintable changed files, `build` as a sanity check — no qa-sentinel, no test suite), then proceed to Phase 3 (doc review, which DOES run) and Phase 4 (commit). Log `simplify/qa/codex: SKIPPED (trivial — non-source diff)`. If the actual diff turned out to contain a source file → NOT trivial → run this phase and the normal review path. AC-Closure (Phase 2.5b) already ran and is never skipped.
|
|
8
|
+
|
|
9
|
+
After completeness is verified, clean up the implementation before it reaches reviewers and E2E tests. This phase launches three parallel agents on the card's diff, then applies fixes directly.
|
|
10
|
+
|
|
11
|
+
**Step-by-step**:
|
|
12
|
+
|
|
13
|
+
1. **Update tracker**: phase = "2.55-simplify".
|
|
14
|
+
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).
|
|
15
|
+
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:
|
|
16
|
+
|
|
17
|
+
- **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.
|
|
18
|
+
- **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).
|
|
19
|
+
- **Efficiency agent** — flag unnecessary work (redundant computations, duplicate API calls, N+1), missed concurrency, hot-path bloat, recurring no-op updates without change-detection guards, TOCTOU existence checks, memory issues (unbounded structures, missing cleanup), overly broad operations.
|
|
20
|
+
|
|
21
|
+
4. Aggregate findings from all three agents. For each finding:
|
|
22
|
+
- **Valid AND in a Domain-Override domain** (the finding's target file matches the `doc`, `security`, or `migration` match rule in "Domain-Override Domains") → do NOT apply inline. Delegate to the domain owner: `doc` → `doc-reviewer` (write mode), `security`/`migration` → `coder`. Even a one-line efficiency fix in `paths.high_risk_modules` or a migration file goes to the owning agent — the orchestrator lacks that domain's invariant contract.
|
|
23
|
+
- **Valid AND not in a Domain-Override domain** → fix directly (apply edits inline).
|
|
24
|
+
- **False positive / not worth addressing** → skip, BUT record it (see telemetry). If the skip rests on a "covered by X" / "redundant" / "not needed" rationalization (the same family the AC-Closure Gate guards against), do NOT discard silently — verify the rationale by reading `X`, and if it does not hold, treat the finding as valid.
|
|
25
|
+
|
|
26
|
+
**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>`.
|
|
27
|
+
|
|
28
|
+
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).
|
|
29
|
+
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.
|
|
30
|
+
|
|
31
|
+
6. **Update tracker**: phase = "2.55-simplify DONE", log count of fixes applied (or "clean — 0 fixes").
|
|
32
|
+
If any valid finding revealed a reusable pattern or common mistake, append 1-line to `## Lessons Learned`:
|
|
33
|
+
`SIMPLIFY: <pattern> — <file>`
|
|
34
|
+
|
|
35
|
+
### Phase 2.6 — End-to-End Review (BLOCKING, since v3.18.0)
|
|
36
|
+
|
|
37
|
+
This phase delegates to the `/e2e-review` skill — a deterministic, BLOCKING
|
|
38
|
+
orchestrator that combines functional E2E (Playwright spec written by `coder`,
|
|
39
|
+
executed via `playwright-skill`) with visual fidelity diff
|
|
40
|
+
(`visual-fidelity-verifier` multimodal agent), aggregates findings under a
|
|
41
|
+
strict severity gate, runs a bounded self-heal loop, and either passes /
|
|
42
|
+
blocks / accepts an explicit user override.
|
|
43
|
+
|
|
44
|
+
The skill replaces the previous advisory pair (legacy Phase 2.6 E2E testing
|
|
45
|
+
and Phase 2.7 visual design review). It runs by default on every UI card,
|
|
46
|
+
auto-skips on backend-only cards, and BLOCKS the commit on gating findings.
|
|
47
|
+
|
|
48
|
+
#### Gate (skip the whole phase when any of the below is true)
|
|
49
|
+
|
|
50
|
+
| Condition | Action |
|
|
51
|
+
|-----------|--------|
|
|
52
|
+
| `features.has_e2e_review: false` in `baldart.config.yml` | **SKIP** — log `"e2e-review: SKIP (feature disabled — run `npx baldart configure` to enable)"`. Preserves backwards compatibility for pre-3.18 consumers. |
|
|
53
|
+
| Card has no `links.design` AND the card's diff (`git diff --name-only "$TRUNK...HEAD"` for this card's committed files, falling back to `HEAD~1..HEAD`) shows no file under `${paths.app_dir}` AND no file under `${paths.components_primitives}` AND no `*.tsx` / `*.css` / `*.scss` / `*.svelte` / `*.vue` anywhere | **SKIP** — log `"e2e-review: SKIP (backend-only card)"`. (Diff against the trunk, NOT a bare `HEAD` — the coder already committed, so a working-tree diff is empty and would false-skip.) |
|
|
54
|
+
| Card type is `backend`, `api`, `db`, `infra`, `docs`, `chore`, or `config` | **SKIP** — same log. (This list mirrors `/e2e-review`'s OWN Pre-flight skip set so `/new` does not invoke the skill only to have it immediately return `skipped`. A card with no `type` field falls through to the diff-based backend-only check above — do NOT assume a missing type means skip.) |
|
|
55
|
+
|
|
56
|
+
#### Invocation contract
|
|
57
|
+
|
|
58
|
+
When the gate above passes, the orchestrator invokes `/e2e-review` in
|
|
59
|
+
**programmatic mode**:
|
|
60
|
+
|
|
61
|
+
1. **Update tracker**: phase = "2.6-e2e-review".
|
|
62
|
+
2. Spawn the skill with the payload:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"card_id": "<CARD-ID>",
|
|
67
|
+
"worktree_path": "<absolute worktree path>",
|
|
68
|
+
"mode": "programmatic"
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Do NOT pass `tolerance` / `max_self_heal_iterations` in the payload — `/e2e-review` reads those from `features.e2e_review.*` in `baldart.config.yml` itself (they are NOT parsed from the invocation payload). Passing them here would be dead keys that silently diverge from the config the skill actually uses.
|
|
73
|
+
|
|
74
|
+
The skill is responsible for: reading the card YAML + `test_plan`, deriving
|
|
75
|
+
routes from the diff, walking the 4-level mockup cascade (Figma MCP →
|
|
76
|
+
local image → compliance-only → skip), generating the Playwright spec via
|
|
77
|
+
`coder`, executing it headless, invoking `visual-fidelity-verifier` per
|
|
78
|
+
route, and returning a single JSON object.
|
|
79
|
+
|
|
80
|
+
3. Parse the returned JSON. The contract is:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"status": "passed" | "blocked" | "overridden" | "skipped" | "error",
|
|
85
|
+
"iterations": 0,
|
|
86
|
+
"findings": [ ... ],
|
|
87
|
+
"ds_drift_codes": [ "DS_TOKENS_DRIFT" | "DS_COMPONENT_STALE" | "DS_INDEX_DRIFT" ],
|
|
88
|
+
"gaps": [ ... ],
|
|
89
|
+
"transcript_paths": [ ... ]
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Gating logic (BLOCKING)
|
|
94
|
+
|
|
95
|
+
| `status` from `/e2e-review` | Orchestrator action |
|
|
96
|
+
|----|----|
|
|
97
|
+
| `"passed"` | Log result in tracker. Proceed to Phase 3 (doc review + code review). |
|
|
98
|
+
| `"skipped"` | Log skip reason. Proceed to Phase 3. |
|
|
99
|
+
| `"overridden"` | Log override + reason in `## Issues & Flags` as `[E2E-OVERRIDE] <reason>`. Proceed to Phase 3. |
|
|
100
|
+
| `"blocked"` | **STOP the card**. Log findings in tracker + `## Issues & Flags` as `[E2E-BLOCKED] <count> gating findings (<categories>)`. Ask the user whether to (a) override with reason, (b) escalate (open follow-up card), or (c) abandon this card and continue the batch. Do NOT proceed to Phase 3 silently. |
|
|
101
|
+
| `"error"` | Log error in `## Issues & Flags`. Ask the user whether to retry, skip, or abandon. Do NOT proceed silently. **Retry re-entry (defined path, capped):** on "retry", re-enter at step 1 of this Invocation contract — reset the `.baldart/e2e-review/<CARD-ID>/` state dir, re-spawn `/e2e-review` with the SAME payload, and re-parse. **Cap: 2 error-retries per card** (central repair cap, consistent with the other loops). On the 2nd `error`, do NOT re-offer "retry" — re-invoke `AskUserQuestion` with only skip/abandon, so the loop cannot recur unbounded. |
|
|
102
|
+
|
|
103
|
+
#### Re-run trigger (after Phase 3.7 `/codexreview`)
|
|
104
|
+
|
|
105
|
+
If the mandatory `/codexreview` gate in Phase 3.7 modifies any file under
|
|
106
|
+
`${paths.app_dir}`, `${paths.components_primitives}`, or any `*.css` /
|
|
107
|
+
`*.scss`, the orchestrator MUST re-invoke `/e2e-review` BEFORE the Phase 4
|
|
108
|
+
commit. This protects against code-review changes that silently reintroduce
|
|
109
|
+
visual / functional drift. The re-run reuses the same
|
|
110
|
+
`.baldart/e2e-review/<CARD-ID>/` state directory and starts from Phase 3
|
|
111
|
+
of the skill (skipping plan extraction and mockup cascade).
|
|
112
|
+
|
|
113
|
+
#### Tracker output
|
|
114
|
+
|
|
115
|
+
Append to `## Current Card` and (on completion) carry into `## Completed Cards`:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
e2e-review: <status> | iterations: <N> | findings: <X critical, Y major, Z minor> | drift: [<codes>] | tolerance: <strict|balanced|lenient>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Out of scope for this phase
|
|
122
|
+
|
|
123
|
+
- Mockup re-design (the skill never modifies the mockup — only the
|
|
124
|
+
implementation).
|
|
125
|
+
- Code review or doc review (those remain Phase 3 / 3.7 responsibilities).
|
|
126
|
+
- Unit-test execution (that is `qa-sentinel`).
|
|
127
|
+
- Visual polish beyond gating findings (advisory Minor findings under
|
|
128
|
+
balanced/lenient tolerance are logged but not actioned).
|
|
129
|
+
|
|
130
|
+
#### Legacy cards
|
|
131
|
+
|
|
132
|
+
Cards written before v3.18.0 (without a `test_plan` block) still work — the
|
|
133
|
+
skill's Phase 1 falls back to deriving Gherkin scenarios from
|
|
134
|
+
`acceptance_criteria` directly. The mockup cascade gracefully degrades when
|
|
135
|
+
`links.design` is missing.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Phase 3 — Doc Review & Sync (code review handled by mandatory Phase 3.7 gate)
|
|
140
|
+
|
|
141
|
+
> **Note**: Code review is NOT performed in this phase — it is handled by the **mandatory unconditional `/codexreview` gate in Phase 3.7**, which runs per-card BEFORE the Phase 4 commit. The post-batch `/codexreview` in the Final review remains as a final FULL-diff sweep over the entire batch (since v3.37.0 — the guaranteed full-depth merge gate). This Phase 3 focuses exclusively on documentation sync, which must happen per-card (tied to the specific commit).
|
|
142
|
+
|
|
143
|
+
> **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`.
|
|
144
|
+
|
|
145
|
+
12. **Update tracker**: phase = "3-doc-review".
|
|
146
|
+
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):
|
|
147
|
+
```bash
|
|
148
|
+
git diff --name-only "$TRUNK...HEAD" 2>/dev/null || git diff --name-only HEAD~1..HEAD
|
|
149
|
+
```
|
|
150
|
+
Use the output to build this block:
|
|
151
|
+
```
|
|
152
|
+
## Doc Sync Context
|
|
153
|
+
|
|
154
|
+
### Changed code files (for freshness mapping):
|
|
155
|
+
[list all code files changed — src/, scripts/, etc.]
|
|
156
|
+
|
|
157
|
+
### Invariant checklist (Linking Protocol — docs/guides/linking-protocol-rollout-v1.md):
|
|
158
|
+
- [ ] New route.ts added? → ${paths.references_dir}/api/<module>.md + api/index.md count
|
|
159
|
+
- [ ] New page.tsx added? → ${paths.references_dir}/ui/<domain>.md + ui/index.md Route Summary
|
|
160
|
+
- [ ] New persistence-layer {entity} ({collection|table|item} per `stack.database`)? → ${paths.references_dir}/data-model.md + the entity's reference doc per project convention (`collections/<domain>.md`, `tables/<domain>.md`, etc.)
|
|
161
|
+
- [ ] Compound query needing a multi-attribute index? → the matching index artifact MUST be staged in the same commit, per `stack.database`: `firestore.indexes.json` (firestore), migration file or Prisma `@@index` (SQL), `createIndex` script (mongo), GSI/LSI in IaC (dynamodb)
|
|
162
|
+
- [ ] Backlog card set to DONE? → ${paths.references_dir}/ssot-registry.md entry
|
|
163
|
+
- [ ] New external dependency? → agents/architecture.md External Dependencies list
|
|
164
|
+
- [ ] Card has `documentation_impact` field? → verify each listed doc is updated
|
|
165
|
+
- [ ] New `process.env.VAR` added? → entry in `${paths.references_dir}/env-vars.md` (name, scope, required, feature/card, default)
|
|
166
|
+
- [ ] Last usage of `process.env.VAR` removed? → mark `status: deprecated` in `${paths.references_dir}/env-vars.md` with the date
|
|
167
|
+
- [ ] Default value changed in the project's env module (e.g. `src/lib/env.ts`)? → update the Default column in `${paths.references_dir}/env-vars.md`
|
|
168
|
+
- [ ] Card has an `env_vars` field populated? → verify each entry is tracked in `${paths.references_dir}/env-vars.md`
|
|
169
|
+
|
|
170
|
+
### Related docs to check (per convention map):
|
|
171
|
+
- [derive from FRESHNESS_MAP: src/app/api/** → ${paths.references_dir}/api/; src/lib/booking/** → booking.md etc.]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Invoke the **doc-reviewer** agent in **audit-and-apply mode** (single invocation — it both finds the gaps AND fixes them, per `doc-reviewer.md` § Constraints), passing the Doc Sync Context:
|
|
175
|
+
```
|
|
176
|
+
Doc Sync Context:
|
|
177
|
+
[paste the Doc Sync Context block built above]
|
|
178
|
+
|
|
179
|
+
Instructions for doc-reviewer:
|
|
180
|
+
- You OWN the `doc` domain end-to-end: audit AND apply the fixes in THIS invocation.
|
|
181
|
+
Do NOT defer doc writes to another agent — you are the agent with the doc-invariant
|
|
182
|
+
contract and the full context. Write the missing/stale docs directly.
|
|
183
|
+
- Set freshness_status: fresh and last_verified_from_code: <today's date> on any doc you touch
|
|
184
|
+
- Check each invariant in the checklist above and fix any that are unmet
|
|
185
|
+
- Update any doc in "Related docs to check" that should be marked stale/fresh
|
|
186
|
+
- Run your standard doc audit on all changed files and apply the corrections
|
|
187
|
+
- **Spec/docs-drift → bug lens (MANDATORY since v3.35.0)**: flag any place where the
|
|
188
|
+
implementation contradicts a documented contract/spec in a way that can cause incorrect
|
|
189
|
+
behavior (response shape diverging from `api/<module>.md`, field semantics diverging from
|
|
190
|
+
`data-model.md`, etc.). This lens was previously exclusive to `/codexreview` agent #4; the
|
|
191
|
+
per-card Phase 3.7 gate now skips that duplicate (lean mode), so THIS pass MUST carry it.
|
|
192
|
+
A doc-drift→bug finding whose root cause is in CODE (not the doc) is the ONE thing
|
|
193
|
+
doc-reviewer does NOT fix itself — report it with the conflicting code location + the doc
|
|
194
|
+
it violates, and the orchestrator routes it to the `security`/code fix path as appropriate.
|
|
195
|
+
```
|
|
196
|
+
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.
|
|
197
|
+
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.
|
|
198
|
+
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.)
|
|
199
|
+
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).
|
|
200
|
+
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.
|
|
201
|
+
If doc-reviewer found a recurring gap, append 1-line to `## Lessons Learned`:
|
|
202
|
+
`DOC: <pattern>`
|
|
203
|
+
|
|
204
|
+
### Phase 3.5 — QA Validation
|
|
205
|
+
|
|
206
|
+
18. **Update tracker**: phase = "3.5-qa".
|
|
207
|
+
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).
|
|
208
|
+
20. **If profile is SKIP**: log "QA skipped — [reason]" in the tracker. Proceed to Phase 4.
|
|
209
|
+
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.
|
|
210
|
+
21b. **If profile is BALANCED (since v4.7.0 — deferral to Final, enumerated `review_profile`-driven)**: SKIP per-card qa-sentinel and **defer the test suite to the Final Review F.3 qa-sentinel** (which runs the FULL suite + build + audit over the entire batch — the unconditional merge gate). Phase 2 step 8 already ran lint/tsc/test/build on this card's diff. **Exception — risk escalation runs FULL per-card anyway**: if the Phase 3.7 Step A detector matched any high-risk trigger on this card's diff (auth/permission/payment/schema/migration/API-contract), do NOT defer — run qa-sentinel at FULL here for fail-fast. Log `QA balanced deferred to Final FULL gate (no risk escalation)` or `QA balanced escalated to FULL (risk drift: <trigger>)`. ⚠️ Most `feature`/`enhancement` cards are `balanced` (Rule C), so a balanced-only batch first runs the suite at the Final gate; the merge gate stays safe (Final = full suite over the whole batch). Proceed to Phase 4 when deferred.
|
|
211
|
+
22. **If profile is DEEP (or BALANCED escalated by risk drift — see 21b)**: invoke the **`qa-sentinel`** agent (subagent_type: `qa-sentinel`) via Task tool with the following context:
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
Run QA gates on card <CARD-ID> at the tier dictated by the QA profile below (do NOT default to FULL).
|
|
215
|
+
You are a MECHANICAL GATE-RUNNER: run the gates, return a PASS/FAIL gate table + confidence.
|
|
216
|
+
Do NOT read source files to analyze logic, do NOT emit a BLOCKER/MAJOR/MINOR severity taxonomy,
|
|
217
|
+
do NOT do collateral-impact analysis, and do NOT write tests.
|
|
218
|
+
|
|
219
|
+
Context:
|
|
220
|
+
- Worktree path: <worktree-path> — `cd` into it before running any gate
|
|
221
|
+
- Branch: <branch-name>
|
|
222
|
+
- Changed files: <list from implementation phase>
|
|
223
|
+
- QA profile: [deep | balanced-escalated]
|
|
224
|
+
|
|
225
|
+
Tier contract: deep → FULL suite. A BALANCED card only reaches this step when risk drift
|
|
226
|
+
escalated it (step 21b) — run it at FULL too (the escalation reason is the fail-fast signal).
|
|
227
|
+
A non-escalated balanced card never reaches here (its suite is deferred to the Final FULL gate
|
|
228
|
+
per step 21b). File count never escalates.
|
|
229
|
+
|
|
230
|
+
E2E is NOT your job (run by the /e2e-review skill in Phase 2.6) — do NOT run Playwright.
|
|
231
|
+
Run the gates: lint, tsc (when stack.language includes typescript), test (per tier), build, markdownlint.
|
|
232
|
+
Do NOT verify acceptance criteria (Phase 2.5 already did this).
|
|
233
|
+
Do NOT analyze code for bugs/patterns (the per-card /codexreview gate in Phase 3.7 does this).
|
|
234
|
+
|
|
235
|
+
Write the gate results + verdict to: /qa/<CARD-ID>.md
|
|
236
|
+
Report should be under 40 lines.
|
|
237
|
+
Return verdict: PASS or FAIL (+ the per-gate table).
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
23. **Read qa-sentinel's output.** Verify the findings file was written to `/qa/<CARD-ID>.md`. **If the file is absent** (qa-sentinel returned a verdict but did not write it): re-invoke qa-sentinel once asking it to (re-)write the file; if still absent, treat the verdict from the return message as authoritative, log `[QA] findings file missing — used return verdict` in `## Issues & Flags`, and pass the captured gate output (not a missing path) to any fix coder.
|
|
241
|
+
24. **If QA verdict is FAIL** (one or more gates failed):
|
|
242
|
+
- Spawn the **coder** agent to fix the FAILING GATES (pass it the findings file path + the failing-gate output — NOT a severity-ranked finding list; qa-sentinel does not emit one). Do NOT ask the user.
|
|
243
|
+
- After coder fixes, re-invoke `qa-sentinel` in the same mode to re-validate. Repeat up to **2 times**.
|
|
244
|
+
- If still FAIL after 2 retries: log in `## Issues & Flags` and **ask the user** whether to proceed or stop.
|
|
245
|
+
- The commit in Phase 4 MUST NOT happen until QA verdict is PASS (or user explicitly overrides).
|
|
246
|
+
- **Telemetry** — after each coder spawn, append one row per failing-gate fix to `## Fix Application Log`: `3.5 | qa-blocker | est_lines=<n> | decision=coder | applied_by=coder | retry=<0|1|2>`. After PASS without any spawn (initial verdict PASS), append one row: `3.5 | qa-none | est_lines=0 | decision=skipped | applied_by=- | reason=qa-pass`.
|
|
247
|
+
25. **Update tracker**: phase = "3.5-qa DONE", log: profile used, tier run (SCOPED/FULL) + any risk-drift escalation, verdict (PASS/FAIL/SKIP), confidence %, failing gates (which of lint/tsc/test/build/markdownlint), findings file path. (qa-sentinel returns a per-gate PASS/FAIL table, not a blockers/majors/minors split — do not invent one.) **Phase-8 producer (named flag)** — ALSO record `qa_first_attempt: <pass|fail>` on the card's `## Completed Cards` QA line: `pass` ⟺ the FIRST qa-sentinel invocation (step 22, retry=0) returned PASS with no step-24 coder spawn; `fail` ⟺ a retry was needed (or the profile reached PASS only after a fix). For `SKIP`/`LIGHT` cards (qa-sentinel not run) record `qa_first_attempt: n/a`. This is the single named producer for Phase 8's `qa_pass_first_attempt_rate` — the tracker otherwise logs only the final verdict, so the first-attempt signal must be tagged here at the source.
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
<!-- Modulo on-demand di /new — NON un file installato a sé. Caricato via Read dalla § "Routing" del SKILL.md core. -->
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
## Phase 0 — Workspace Hygiene Pre-flight (BLOCKING — non-skippable)
|
|
6
|
+
|
|
7
|
+
**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.
|
|
8
|
+
|
|
9
|
+
**Auto Mode does NOT override this phase.** Every `AskUserQuestion` below is non-bypassable — the model has no authority to pick an option on the user's behalf.
|
|
10
|
+
|
|
11
|
+
**Steps:**
|
|
12
|
+
|
|
13
|
+
0. **Feature gate + config resolution (BLOCKING)** — before anything else:
|
|
14
|
+
- Read `features.has_backlog` from `baldart.config.yml`. If it is `false` (or the key is absent and the user confirms there is no backlog), this skill REFUSES to run: print "`/new` operates on backlog cards and requires `features.has_backlog: true` — run `npx baldart configure` to enable." and HALT. Do NOT proceed to step 1.
|
|
15
|
+
- Resolve `$TRUNK` = `git.trunk_branch` from `baldart.config.yml`. **When the key is absent** (consumer updated to ≥4.0.0 without re-running `configure`), do NOT hard-assume `develop` — autodetect the repo's real default branch exactly as worktree-manager does, so `/new` and `nw` agree on the base: `git -C "$MAIN" symbolic-ref --quiet refs/remotes/origin/HEAD` (strip `refs/remotes/origin/`), else the first existing local branch among `develop` / `main` / `master`. A `main`-trunk repo defaulted to `develop` here would diverge from the worktree base `nw` picks and break every `git diff "$TRUNK...HEAD"` gate. Only HALT ("Trunk branch unresolved — run `npx baldart configure`") if nothing resolves. Persist the resolved value as `Trunk branch:` in the tracker `## Worktree` section. **Every later Phase 0 / Phase 6c bash snippet that references the integration trunk MUST use `$TRUNK`, never a baked-in `develop`.** Begin every later consumer with a guard: if `$TRUNK` is empty → HALT with "Trunk branch unresolved — re-read `git.trunk_branch` from the tracker".
|
|
16
|
+
- Resolve `$METRICS` = `paths.metrics` from `baldart.config.yml` (default `docs/metrics`). This is the framework-owned telemetry directory written by Phase 8 (tracker archive, `skill-runs.jsonl`, `sessions/`). The dirty-tree gate (step 3) reads `$METRICS` to recognise — and never surface — its own telemetry output. Persist it as `Metrics dir:` in the tracker `## Worktree` section.
|
|
17
|
+
|
|
18
|
+
1. **Resolve `$MAIN`** — the absolute path of the main repo (not a worktree). If `/new` was invoked from inside a worktree, walk up to the parent repo via `git rev-parse --show-superproject-working-tree` or `git worktree list` until you find the non-worktree root. Persist as `Main repo:` in the tracker `## Worktree` section. **Write `$MAIN` to the tracker the moment it is computed** — every later consumer (Phase 6c, Phase 6b) MUST re-read it from the tracker and HALT with "`$MAIN` absent from tracker" if the field is missing or empty, never silently use an undefined `$MAIN` (it does not survive context compaction).
|
|
19
|
+
|
|
20
|
+
2. **Fetch remote state**:
|
|
21
|
+
```bash
|
|
22
|
+
git -C "$MAIN" fetch origin --quiet
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. **Dirty-tree gate (BLOCKING — framework telemetry AND BALDART-managed artifacts are auto-ignored, never surfaced)** — capture the working tree state of the main repo, then **partition it** so the gate fires only on genuine in-progress user work:
|
|
26
|
+
```bash
|
|
27
|
+
PORCELAIN="$(git -C "$MAIN" status --porcelain)"
|
|
28
|
+
# Drop two classes of framework-owned noise that are NOT user work:
|
|
29
|
+
# (a) telemetry THIS skill writes in Phase 8 (tracker archive, skill-runs.jsonl,
|
|
30
|
+
# sessions/) under $METRICS and never commits;
|
|
31
|
+
# (b) BALDART-managed install artifacts written by `baldart update`/`add`/`push`:
|
|
32
|
+
# .baldart/generated/ (overlay-merged agents/commands), .baldart/state.json
|
|
33
|
+
# (versioning ledger), .baldart/skill-conflicts.json. These ARE meant to be
|
|
34
|
+
# committed, but a reinstall/update leaves them dirty BEFORE the consumer has
|
|
35
|
+
# committed them — they are framework output, not feature work.
|
|
36
|
+
# NOTE: .baldart/overlays/ is deliberately NOT in this set — overlays are user-owned;
|
|
37
|
+
# an edited overlay IS genuine work and MUST still gate.
|
|
38
|
+
# Porcelain lines are "XY path"; paths with special chars are quoted. $METRICS from step 0.
|
|
39
|
+
USER_DIRTY="$(printf '%s\n' "$PORCELAIN" \
|
|
40
|
+
| grep -vE "^.{3}\"?${METRICS}/" \
|
|
41
|
+
| grep -vE "^.{3}\"?${METRICS}\"?$" \
|
|
42
|
+
| grep -vE "^.{3}\"?\.baldart/(generated/|state\.json|skill-conflicts\.json)" \
|
|
43
|
+
| grep -v '^[[:space:]]*$')"
|
|
44
|
+
```
|
|
45
|
+
**Why**: Phase 8 copies the batch tracker into `$METRICS/archive/` and appends to `$METRICS/skill-runs.jsonl` *after* the merge, and never commits them. And `baldart update`/`add` regenerate `.baldart/generated/*` + bump `.baldart/state.json` on every framework sync — left uncommitted until the next reconcile. If either class tripped this gate, **every batch would block on the previous update's own output** — a self-inflicted loop. They are not user work and the user is never asked about them.
|
|
46
|
+
- If `$PORCELAIN` is non-empty but `$USER_DIRTY` is **empty** (only telemetry under `$METRICS` and/or BALDART-managed `.baldart/` artifacts are dirty) → do **NOT** gate. Write `Dirty: framework-managed-only (auto-ignored)` to the tracker and proceed to step 4. No `AskUserQuestion`.
|
|
47
|
+
- If `$USER_DIRTY` is **non-empty** (genuine uncommitted user work) → invoke `AskUserQuestion`:
|
|
48
|
+
- Question: `"Main repo ($MAIN) ha modifiche non committate prima di partire con la batch. Come procedo?"`
|
|
49
|
+
- Options (max 4):
|
|
50
|
+
1. **"Stash automatico (restore in Phase 6c)"** — `$MAIN` is the main checkout (NOT a worktree), so a stash here is safe. Run `git -C "$MAIN" stash push -u -m "baldart-new-phase0-<FIRST-CARD-ID>-<timestamp>"` and write the **stash MESSAGE label** (`baldart-new-phase0-<FIRST-CARD-ID>-<timestamp>`) to the tracker under `## Workspace Snapshot: <message-label> (created <timestamp>)`. Phase 6c resolves the stash by this message — NEVER by a positional `stash@{N}`, because other stashes pushed during the batch (on the main checkout) would shift the index. Do NOT record `stash@{0}`.
|
|
51
|
+
2. **"Committa adesso (apri editor)"** — halt the batch with a clear message asking the user to commit in their terminal and re-invoke `/new`. Do NOT proceed to step 4.
|
|
52
|
+
3. **"Procedi senza stash (lavoro mio, lo gestisco io)"** — explicit user override. Log in tracker: `## Workspace Snapshot: dirty-tree override @ <timestamp> — user accepted responsibility`. Phase 6c will still check post-merge state but will NOT attempt restore.
|
|
53
|
+
4. **"Abort batch"** — halt the batch, leave the tracker file in place, exit.
|
|
54
|
+
|
|
55
|
+
Do NOT silently proceed. Do NOT auto-stash without the user picking option 1.
|
|
56
|
+
|
|
57
|
+
4. **Divergence gate (BLOCKING — framework-management commits do NOT count as orphan commits)** — compare local `$TRUNK` against `origin/$TRUNK` (the trunk resolved in step 0):
|
|
58
|
+
```bash
|
|
59
|
+
read BEHIND AHEAD <<< "$(git -C "$MAIN" rev-list --left-right --count "origin/$TRUNK...$TRUNK")"
|
|
60
|
+
```
|
|
61
|
+
`$BEHIND` / `$AHEAD` are the raw counts. Before branching, **reclassify the ahead commits**: commits produced by `baldart update`/`baldart add` (subtree merges into `.framework/`, the `[CHORE] baldart update …` commit, and the regenerated overlay files they carry) are *expected* divergence, not the FEAT-0006 orphan-commit pattern. Count only **genuine** unpushed commits:
|
|
62
|
+
```bash
|
|
63
|
+
GENUINE_AHEAD=0; GENUINE_LIST=""; FW_SKIPPED=0
|
|
64
|
+
for sha in $(git -C "$MAIN" rev-list "origin/$TRUNK..$TRUNK"); do
|
|
65
|
+
subj="$(git -C "$MAIN" log -1 --format=%s "$sha")"
|
|
66
|
+
# subtree merge (e.g. "Merge commit '…' as '.framework'") or baldart update/add chore
|
|
67
|
+
if printf '%s' "$subj" | grep -qE "as '\.framework'" || printf '%s' "$subj" | grep -qiE "baldart (update|add)"; then
|
|
68
|
+
FW_SKIPPED=$((FW_SKIPPED+1)); continue
|
|
69
|
+
fi
|
|
70
|
+
# touches ONLY framework-managed paths? (empty file list = merge commit, handled above)
|
|
71
|
+
# - .framework/ (subtree payload)
|
|
72
|
+
# - .baldart/generated/, .baldart/state.json, .baldart/skill-conflicts.json
|
|
73
|
+
# (artifacts a reinstall/update commits: regenerated overlay files + version ledger)
|
|
74
|
+
# .baldart/overlays/ is intentionally EXCLUDED — an overlay edit is genuine user work.
|
|
75
|
+
files="$(git -C "$MAIN" show --pretty=format: --name-only "$sha" | grep -v '^$')"
|
|
76
|
+
if [ -n "$files" ] && ! printf '%s\n' "$files" | grep -qvE '^(\.framework/|\.baldart/(generated/|state\.json|skill-conflicts\.json))'; then
|
|
77
|
+
FW_SKIPPED=$((FW_SKIPPED+1)); continue
|
|
78
|
+
fi
|
|
79
|
+
GENUINE_AHEAD=$((GENUINE_AHEAD+1)); GENUINE_LIST="$GENUINE_LIST $sha"
|
|
80
|
+
done
|
|
81
|
+
```
|
|
82
|
+
`$FW_SKIPPED` framework-management commits are auto-ignored (log them — see below). Branch on `$BEHIND` and the **genuine** ahead count `$GENUINE_AHEAD` (NOT the raw `$AHEAD`):
|
|
83
|
+
|
|
84
|
+
- **`BEHIND=0` and `GENUINE_AHEAD=0`** — synchronized for `/new`'s purposes. If `$FW_SKIPPED > 0`, write `Divergence: $FW_SKIPPED framework-management commits ahead (auto-ignored — baldart update/subtree)` to the tracker. **No `AskUserQuestion`.** Proceed to step 5.
|
|
85
|
+
- **`BEHIND>0` and `GENUINE_AHEAD=0`** (only behind) — invoke `AskUserQuestion`:
|
|
86
|
+
- Question: `"Local $TRUNK è behind origin/$TRUNK di $BEHIND commit. Come procedo?"`
|
|
87
|
+
- Options: `[Fast-forward pull adesso]` / `[Procedi senza pull]` / `[Abort]`.
|
|
88
|
+
- On `Fast-forward pull adesso`: if `$MAIN` HEAD == `$TRUNK`, run `git -C "$MAIN" pull --ff-only origin "$TRUNK"`; otherwise log "main HEAD is `<branch>` — fetch already updated `refs/remotes/origin/$TRUNK`, local `$TRUNK` ref will be reconciled in Phase 6c".
|
|
89
|
+
- **`BEHIND=0` and `GENUINE_AHEAD>0`** (genuine UNPUSHED LOCAL COMMITS, this is the FEAT-0006 pattern) — invoke `AskUserQuestion`:
|
|
90
|
+
- Question: `"Local $TRUNK è ahead di origin/$TRUNK di $GENUINE_AHEAD commit locali non pushati (esclusi $FW_SKIPPED commit di gestione framework). Cosa faccio?"`
|
|
91
|
+
- Show **only the genuine** commits inline: `git -C "$MAIN" show -s --oneline $GENUINE_LIST`.
|
|
92
|
+
- Options: `[Push adesso (git push origin $TRUNK)]` / `[Cherry-pick a parte e continua]` / `[Lascia così e procedi (lo gestisco io)]` / `[Abort]`.
|
|
93
|
+
- **`BEHIND>0` and `GENUINE_AHEAD>0`** (diverged both ways) — invoke `AskUserQuestion`:
|
|
94
|
+
- Question: `"Local $TRUNK è diverged da origin/$TRUNK: $BEHIND behind, $GENUINE_AHEAD genuine ahead. Servono entrambe le riconciliazioni. Come procedo?"`
|
|
95
|
+
- Options: `[Rebase local $TRUNK su origin/$TRUNK]` / `[Mostrami i commit e fammi decidere]` / `[Abort]`.
|
|
96
|
+
|
|
97
|
+
5. **Log and proceed** — write to the tracker:
|
|
98
|
+
```
|
|
99
|
+
## Phase 0 — Workspace Hygiene Pre-flight
|
|
100
|
+
Status: PASS
|
|
101
|
+
Main repo: $MAIN
|
|
102
|
+
Trunk branch: $TRUNK
|
|
103
|
+
Dirty: <none | framework-managed-only (auto-ignored) | stashed: <message-label> | user-override>
|
|
104
|
+
Divergence (local…origin/$TRUNK): <0\t0 | framework-mgmt-only (auto-ignored: $FW_SKIPPED) | resolved: ff-pull | resolved: pushed | user-deferred>
|
|
105
|
+
Completed: <timestamp>
|
|
106
|
+
```
|
|
107
|
+
If any step ended in HALT, set `Status: HALT` and stop — do NOT continue to `## Pre-flight (once)`.
|
|
108
|
+
|
|
109
|
+
6. **Anti-bypass guard** — before exiting Phase 0, re-read the tracker section you just wrote. If `## Phase 0` is missing or shows `Status: HALT`, refuse to proceed. There is no `--skip-phase-0` flag; if you find yourself reaching for one, treat it as a self-correction trigger and stop.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Pre-flight (once)
|
|
114
|
+
|
|
115
|
+
1. Read each backlog card from `${paths.backlog_dir}/*.yml` to understand scope and dependencies. Also read the project's canonical-docs registry — typically `${paths.references_dir}/ssot-registry.md` plus any linking-protocol guide — to understand which canonical docs exist for the feature area being implemented. Exact filenames are listed in `.baldart/overlays/new.md`; skip when absent.
|
|
116
|
+
1b. **Validate card fields (pre-flight gate)** — for each card, verify it has the minimum required fields before queuing it:
|
|
117
|
+
- `requirements` — must be a non-empty list (>=1 item)
|
|
118
|
+
- `acceptance_criteria` — must be a non-empty list (>=1 item)
|
|
119
|
+
- `files_likely_touched` — must be a non-empty list (>=1 file)
|
|
120
|
+
If any card fails: log the specific missing fields in `## Issues & Flags`, ask the user to fill them in before proceeding with that card, and continue pre-flight for any remaining valid cards.
|
|
121
|
+
|
|
122
|
+
1c. **Field Registry Validation (pre-flight gate)** — for each card with a `data_fields` block, run the project's field-validation tool if available (path listed in `.baldart/overlays/new.md`; typically `python3 tools/validate-card-fields.py <card-yaml-path>`).
|
|
123
|
+
- If exit 1: display the field errors in `## Issues & Flags` and HALT — ask the user to fix the card before proceeding. Do not start implementation until the card passes validation.
|
|
124
|
+
- If the card has DB-index signals (`db_indexes` — or legacy `firestore_indexes` — or `data.collections`/`data.tables`) but NO `data_fields` block: log WARNING in `## Issues & Flags` — "Card `<ID>` touches the persistence layer but has no `data_fields` block. Field/column names are unvalidated."
|
|
125
|
+
- Cards with no `data_fields` and no storage signals: skip silently.
|
|
126
|
+
- If the project does not ship a field-validation tool: skip this step.
|
|
127
|
+
2. Check `${paths.references_dir}/project-status.md` for current state (skip when absent).
|
|
128
|
+
3. Determine which cards can run in **parallel** (no shared files/components) vs which must be **sequential** (dependencies or overlapping paths). Use `group.sequence` to determine execution order within a group.
|
|
129
|
+
3b. **Build a file-ownership map** — for each card, enumerate every source file it is expected to touch (from `claimed_paths`, `paths`, and the implementation plan). Assign each file to **exactly one agent**. If two cards claim the same file, force those cards sequential on a single agent — do NOT spawn them in parallel. Record this map in the tracker under `## File Ownership Map`. This map is the authoritative source for all agent file permissions in Phase 2.
|
|
130
|
+
3c. **Complexity assessment — team mode decision**
|
|
131
|
+
|
|
132
|
+
Determine whether to use **team mode** (parallel coder agents with isolated contexts) or keep **sequential mode** (current behavior).
|
|
133
|
+
|
|
134
|
+
**Decision logic:**
|
|
135
|
+
|
|
136
|
+
1. Read `execution_strategy.recommended_mode` from the epic parent card (if it exists). If present, use it as the default. The `execution_strategy` block is authored by `prd-card-writer` with the canonical shape `groups:` (a list, each entry has `level:` (int) + `cards:` (list)) — consume that shape, not a flat `parallel_group` field.
|
|
137
|
+
2. If no `execution_strategy` exists, compute:
|
|
138
|
+
- Count total cards in batch
|
|
139
|
+
- Count max cards in any single group (from `execution_strategy.groups[].cards`, i.e. cards sharing the same `level`)
|
|
140
|
+
- If no `execution_strategy.groups` exist, compute the levels on-the-fly: build dependency graph from `depends_on`/`blocks`, add conflict edges for cards sharing `(MODIFY)` files, compute topological layers via BFS — each topological layer becomes one group `level`.
|
|
141
|
+
3. Apply threshold:
|
|
142
|
+
- **Sequential mode** if ANY of: total cards <= 3 — OR all cards are in different groups (max group size = 1, nothing to parallelize) — OR all cards form a linear dependency chain.
|
|
143
|
+
- **Team mode** if: total cards > 3 AND at least one group has 2+ cards.
|
|
144
|
+
4. Log decision in tracker:
|
|
145
|
+
```
|
|
146
|
+
## Execution Mode
|
|
147
|
+
Mode: team | sequential
|
|
148
|
+
Reason: [e.g., "6 cards, 3 parallel groups, max 3 cards in group 1"]
|
|
149
|
+
```
|
|
150
|
+
5. Inform the user:
|
|
151
|
+
```
|
|
152
|
+
Batch: N cards, M file unici
|
|
153
|
+
Gruppi paralleli: K livelli, max P card in parallelo
|
|
154
|
+
Modalita: **team mode** / **sequential mode** — [reason]
|
|
155
|
+
```
|
|
156
|
+
Proceed without asking (the PRD already approved the strategy).
|
|
157
|
+
|
|
158
|
+
When `mode == sequential`, the per-card pipeline below runs exactly as documented. The `execution_strategy.groups` levels are simply ignored. When `mode == team`, skip the per-card pipeline and follow the **Team Mode** section at the end of this document.
|
|
159
|
+
|
|
160
|
+
**→ Create the Task spine now.** The execution mode and (in team mode) the wave layout are resolved — create the native Task spine per § "Progress Visibility" A: `Pre-flight` (→ `in_progress`) + one task per card (wave-labelled in team mode) + `Final review` + `Merge & cleanup`. Emit the first Progress Bar with this batch's table. Mark `Pre-flight` → `completed` once worktree setup (step 5) finishes.
|
|
161
|
+
|
|
162
|
+
3d. **Codex batch cross-card grounding check** (runs in background during worktree setup)
|
|
163
|
+
|
|
164
|
+
> **Why**: a non-Anthropic frontier model (Codex, via `codex-companion.mjs`) reviews the full card batch for cross-card conflicts that per-card plan-auditor checks cannot detect (each plan-auditor sees only one card).
|
|
165
|
+
|
|
166
|
+
**Skip decision (provenance-aware — since v4.3.0).** The `/prd` Step 6.6 holistic audit (4-agent team + Codex adversarial pass) ALREADY ran this exact cross-card analysis over the cards when they were authored — its Codex prompt covers `files_likely_touched` conflicts, dependency shadows, implicit ordering, and shared-state mutation across the whole audited set. Re-running here is only worth the Codex call when **something changed between that audit and now**. Compute the skip before launching:
|
|
167
|
+
|
|
168
|
+
1. **Always skip** if the batch has only 1 card (no cross-card conflicts possible).
|
|
169
|
+
2. Otherwise, read `metadata.holistic_audit` from every card in the batch and evaluate the four SKIP conditions — **all must hold**:
|
|
170
|
+
- **S1 — provenance present**: every batch card has `metadata.holistic_audit` with non-empty `audited_at`, `audited_commit`, and `audited_set`. (Missing/partial on any card ⇒ condition fails.)
|
|
171
|
+
- **S2 — jointly audited**: all batch cards carry the **same** `audited_set` value (they were reviewed together, not stitched from separate PRD runs).
|
|
172
|
+
- **S3 — batch ⊆ audited set**: every batch card ID is present in that shared `audited_set`.
|
|
173
|
+
- **S4 — no drift on the claimed paths**: no commit touched any path the batch claims, between the audit baseline and the trunk this run grounds on. Using the shared `audited_commit` (`$AC`) and the batch's union of claimed/touched paths from the file-ownership map (step 3b, `$BATCH_PATHS`):
|
|
174
|
+
```bash
|
|
175
|
+
# empty AC, or AC not in history → treat as drift (do NOT skip)
|
|
176
|
+
DRIFT="$(git -C "$MAIN" log --oneline "$AC".."$TRUNK" -- $BATCH_PATHS 2>/dev/null || echo "DRIFT")"
|
|
177
|
+
```
|
|
178
|
+
S4 holds **iff** `$AC` is non-empty AND the command succeeds AND `$DRIFT` is empty.
|
|
179
|
+
3. **If S1–S4 all hold → SKIP the Codex cross-card check.** Log in the tracker under `## Cross-Card Conflicts (Codex)`:
|
|
180
|
+
`SKIPPED (provenance) — batch ⊆ holistic_audit set <audited_set>, no drift since <AC short sha> (audited <audited_at>)`. Then proceed to step 4 with the file-ownership map unchanged. Do NOT present anything to the user — this is a non-decision.
|
|
181
|
+
4. **Otherwise → RUN the check** (launch below). Record WHY in the same tracker section so the choice is auditable: `RUN — <reason>` where reason is one of `no/partial provenance` (S1) · `batch spans multiple audit sets` (S2) · `batch not a subset of audited set` (S3) · `drift on <first drifted path>` (S4).
|
|
182
|
+
|
|
183
|
+
`$MAIN` and `$TRUNK` are the same variables resolved in Phase 0. This gate degrades safely in every direction: any missing signal, ambiguity, or git error falls through to RUN — never to a silent skip.
|
|
184
|
+
|
|
185
|
+
Launch via `Bash` with `run_in_background: true` and `timeout: 300000`:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
AUDIT_FILE="/tmp/codex-crosscard-<FIRST-CARD-ID>-<SESSION-ID>.md" && \
|
|
189
|
+
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)" && \
|
|
190
|
+
[ -z "$CODEX_SCRIPT" ] && echo "CODEX_NOT_FOUND" > "$AUDIT_FILE" && exit 1; \
|
|
191
|
+
node "$CODEX_SCRIPT" task --wait "
|
|
192
|
+
Cross-card grounding check for a batch of backlog cards about to be implemented together.
|
|
193
|
+
Your job is to find conflicts BETWEEN cards that per-card reviewers would miss.
|
|
194
|
+
|
|
195
|
+
Cards to check (read each file):
|
|
196
|
+
${CARD_PATHS}
|
|
197
|
+
|
|
198
|
+
File-ownership map:
|
|
199
|
+
${FILE_OWNERSHIP_MAP}
|
|
200
|
+
|
|
201
|
+
Check:
|
|
202
|
+
1. FILE CONFLICTS: Do two cards modify the same file in incompatible ways?
|
|
203
|
+
(e.g., Card A adds field X to interface Foo, Card B restructures Foo entirely)
|
|
204
|
+
2. IMPLICIT DEPENDENCIES: Does Card A change a type/function that Card B's
|
|
205
|
+
requirements assume stays unchanged? Flag missing depends_on.
|
|
206
|
+
3. EXECUTION ORDER RISKS: Given the execution_strategy group/level assignments, will parallel
|
|
207
|
+
execution cause merge conflicts or type errors?
|
|
208
|
+
4. SHARED STATE MUTATIONS: Do multiple cards write to the same persistence
|
|
209
|
+
{entity} ({collection|table|item} per `stack.database`) in ways that could
|
|
210
|
+
conflict at runtime?
|
|
211
|
+
|
|
212
|
+
For each finding return:
|
|
213
|
+
- **Cards involved**: CARD-A + CARD-B
|
|
214
|
+
- **Conflict type**: FILE_CONFLICT | IMPLICIT_DEP | ORDER_RISK | STATE_MUTATION
|
|
215
|
+
- **Evidence**: exact field/file from each card
|
|
216
|
+
- **Fix**: concrete recommendation (add depends_on, force sequential, etc.)
|
|
217
|
+
|
|
218
|
+
If no cross-card conflicts: return PASS.
|
|
219
|
+
" > "$AUDIT_FILE" 2>&1
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Variable interpolation**:
|
|
223
|
+
- `${CARD_PATHS}`: newline-separated list of all `- ${paths.backlog_dir}/FEAT-XXXX-*.yml` paths in the batch
|
|
224
|
+
- `${FILE_OWNERSHIP_MAP}`: the file-ownership map built in step 3b
|
|
225
|
+
|
|
226
|
+
> `<SESSION-ID>` is the current session id (e.g. `$CLAUDE_CODE_SESSION_ID`, or a run UUID if unset). The task-scoped unique name prevents two concurrent `/new` sessions on the same day from clobbering each other's findings (a date-only name silently collides). Record the exact `$AUDIT_FILE` path in the tracker under `## Cross-Card Conflicts (Codex)` so the result-handling step reads the SAME path — never re-derive it by wildcard/timestamp.
|
|
227
|
+
|
|
228
|
+
**Result handling** (read before Phase 1 of first card):
|
|
229
|
+
- **Background completion barrier (BLOCKING):** record the background task id when you launch it; do NOT read `$AUDIT_FILE` until that task has completed. Because this gate's verdict steers Phase-1 card ordering, the first card MUST NOT start while the check is in flight.
|
|
230
|
+
- **TIMED_OUT branch:** the launch sets `timeout: 300000` (5 min). If the background task hits the timeout without producing a terminal result (the tail of `$AUDIT_FILE` shows no `PASS` / conflict block / `CODEX_NOT_FOUND`), treat it as **TIMED_OUT** — do NOT leave the task "in-progress" and silently proceed. Log `cross-card-check: TIMED_OUT` in `## Cross-Card Conflicts (Codex)` and take the SAME fallback as `CODEX_NOT_FOUND`: spawn `code-reviewer` over the batch with the four conflict questions. Never start the batch with cross-card review in an unresolved/in-flight state.
|
|
231
|
+
- Read the exact `$AUDIT_FILE` path recorded in the tracker after the background command completes.
|
|
232
|
+
- If the file contains **`CODEX_NOT_FOUND`** (Codex unavailable): do NOT silently proceed — **fallback**: spawn the `code-reviewer` agent over the full batch's card YAMLs + file-ownership map with the same cross-card conflict questions (FILE_CONFLICT / IMPLICIT_DEP / ORDER_RISK / STATE_MUTATION). If `code-reviewer` is also unavailable, surface `CAPABILITY_UNAVAILABLE: cross-card-review` to the user and ask whether to proceed without cross-card detection or halt. Never run a multi-card batch with cross-card review silently skipped.
|
|
233
|
+
- If **PASS** or file empty: proceed normally.
|
|
234
|
+
- If **conflicts found**: log in tracker under `## Cross-Card Conflicts (Codex)` and present to user. For each conflict:
|
|
235
|
+
- `FILE_CONFLICT` / `ORDER_RISK` → force the conflicting cards sequential (update file-ownership map).
|
|
236
|
+
- `IMPLICIT_DEP` → add `depends_on` entry to tracker notes (do NOT modify backlog YAML).
|
|
237
|
+
- `STATE_MUTATION` → add warning to both cards' Phase 2 briefings.
|
|
238
|
+
|
|
239
|
+
4. **Worktree setup** — delegate to the **worktree-manager** skill (`/nw` in programmatic mode):
|
|
240
|
+
a. **Resolve the `slug`** (required by the `/nw` programmatic API — `{ cards, groupParent, slug, branch? }`). Derive it deterministically: if the parent card (or the lead card) has `git_strategy.branch` set, parse the slug from it (`feat/<PARENT-ID>-<slug>` → `<slug>`); otherwise slugify the parent/lead card `title` (lowercase, non-alphanumerics → `-`, collapse repeats, trim, cap ~40 chars). Persist the resolved `slug` in the tracker `## Worktree` section so the path/branch are reproducible across compaction. Do NOT let `/nw` invent its own slug — pass it explicitly.
|
|
241
|
+
b. Pass all card IDs, their `group.parent` fields, AND the resolved `slug` to the skill's grouping logic.
|
|
242
|
+
c. The skill handles: grouping cards by `group.parent`, deriving branch names from `git_strategy.branch` (falling back to `feat/<PARENT-ID>-<slug>` using the slug you passed), creating the worktree in `.worktrees/`, installing dependencies, copying env files, assigning a free port, and verifying the build.
|
|
243
|
+
d. The skill updates `.worktrees/registry.json` with the worktree entry (including all card IDs in the `cards` field).
|
|
244
|
+
e. If build fails → the skill STOPs and reports. Do NOT continue.
|
|
245
|
+
f. Record the worktree path, branch, slug, and port from the skill's output in the tracker.
|
|
246
|
+
5. **Tracker already exists** — the `/tmp/batch-tracker-<FIRST-CARD-ID>.md` file was created at batch start (before Phase 0, see "Context Tracking"). Here, backfill the `## Worktree` section with the worktree path, branch, slug, and port resolved in step 4, AND write `Created: <ISO-8601 now>` (`date -u +%Y-%m-%dT%H:%M:%SZ`) — this is the strategy-independent start anchor Phase 8's `cycle_time_mins` reads. Do NOT re-create the file (Phase 0 has already written to it).
|
|
247
|
+
6. Create a task list to track progress across all cards.
|
|
248
|
+
|
|
249
|
+
---
|