baldart 3.38.0 → 3.39.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 +27 -0
- package/VERSION +1 -1
- package/framework/.claude/skills/new/SKILL.md +8 -3
- package/framework/.claude/skills/prd/references/validation-phase.md +47 -1
- package/framework/.claude/skills/worktree-manager/SKILL.md +54 -6
- package/framework/AGENTS.md +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,33 @@ 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
|
+
## [3.39.0] - 2026-06-01
|
|
9
|
+
|
|
10
|
+
**A `/prd` or `/new` run now CONCLUDES clean — it never ends by handing the user a list of "azioni tue, non bloccanti" (an uncommitted file blocking the local `develop` fast-forward, a merged remote branch left undeleted).** Every workspace-hygiene leftover is either auto-resolved by the finalizer or put behind ONE explicit `AskUserQuestion` gate. No passive manual TODO ever survives into the final summary. **No new `baldart.config.yml` keys.**
|
|
11
|
+
|
|
12
|
+
> **Why.** A `/prd` finalization closed with: *"il develop locale non si è fast-forwardato per una modifica non committata pre-esistente a `docs/metrics/skill-runs.jsonl` — gestisci quel file e poi `git pull --ff-only`"* and *"il branch remoto non è stato eliminato — puoi cancellarlo a mano"*. The orchestrator declared the run "completato" while leaving the workspace half-finished. Root cause: `worktree-manager mw-docs` printed `⚠️ … Leaving as-is` on a blocked fast-forward, and `/prd` (unlike `/new` Phase 6c) had no workspace-hygiene phase to consume that — it forwarded the warning to the user verbatim.
|
|
13
|
+
|
|
14
|
+
### Changed — the merge finalizer auto-resolves instead of giving up
|
|
15
|
+
|
|
16
|
+
- **[framework/.claude/skills/worktree-manager/SKILL.md](framework/.claude/skills/worktree-manager/SKILL.md)** (Common — sync local develop): the blocked-ff path no longer prints `Leaving as-is`. It partitions the dirty tree: the framework-owned append-only telemetry log (`docs/metrics/skill-runs.jsonl`) is reconciled autonomously and losslessly (commit + `pull --rebase` + best-effort push) so the ff completes; ANY foreign file emits a new `[SYNC-NEEDS-DECISION]` marker the orchestrator MUST convert into one explicit gate. Work this run does not own is never auto-committed.
|
|
17
|
+
- **[framework/.claude/skills/worktree-manager/SKILL.md](framework/.claude/skills/worktree-manager/SKILL.md)** (Cleanup step 6.3 + report): merged remote-branch deletion is now an explicit, reported step (was `2>/dev/null || true` silent) — a denial is retried, never degraded into a "puoi cancellarlo a mano" note.
|
|
18
|
+
|
|
19
|
+
### Added — `/prd` Step 7.5 Workspace Hygiene & finalization (BLOCKING)
|
|
20
|
+
|
|
21
|
+
- **[framework/.claude/skills/prd/references/validation-phase.md](framework/.claude/skills/prd/references/validation-phase.md)**: new Step 7.5 mirrors `/new` Phase 6c — consumes the `[SYNC-NEEDS-DECISION]` / `[SYNC-DEFERRED]` markers, raises ONE `AskUserQuestion` per unresolved residue, ensures the merged remote branch is gone. New **HARD RULE** in Final output: the summary MUST NOT contain a "azioni tue / note non bloccanti" section — a run that prints "gestisci tu il file e poi pulla" has FAILED Step 7.5.
|
|
22
|
+
|
|
23
|
+
### Changed — `/new` Phase 6c parses the new marker
|
|
24
|
+
|
|
25
|
+
- **[framework/.claude/skills/new/SKILL.md](framework/.claude/skills/new/SKILL.md)** (Phase 6c step 2): now also parses `[SYNC-NEEDS-DECISION]` (foreign-file ff block / rebase conflict) as a blocking gate, alongside the existing `[SYNC-DEFERRED]`.
|
|
26
|
+
|
|
27
|
+
### Changed — AGENTS.md scopes branch-deletion approval to unmerged branches
|
|
28
|
+
|
|
29
|
+
- **[framework/AGENTS.md](framework/AGENTS.md)**: owner approval is required before deleting an **unmerged** branch; deleting an **already-merged** feature branch is routine cleanup the merge skill performs automatically (no separate approval). The "prune remote branches only when instructed" rule is clarified to exclude a feature branch's own ref on successful merge.
|
|
30
|
+
|
|
31
|
+
### Revert
|
|
32
|
+
|
|
33
|
+
- Restore the `git -C "$MAIN" pull --ff-only origin develop || echo "⚠️ … Leaving as-is."` one-liner in `worktree-manager` and drop `/prd` Step 7.5.
|
|
34
|
+
|
|
8
35
|
## [3.38.0] - 2026-06-01
|
|
9
36
|
|
|
10
37
|
**The per-card review depth (QA + Codex) is now decided deterministically in the backlog card via a new `review_profile` field, computed once at PRD authoring time — instead of being re-derived heuristically by `/new` at runtime.** This removes the implementing agent's interpretation latitude: the card carries `skip|light|balanced|deep`, `/new` READS it, and only falls back to runtime computation for legacy cards that predate the field. **No new `baldart.config.yml` keys** — this is a backlog-card schema change, propagated end-to-end across templates + card-writer + validation + `/new` in the same release.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.39.0
|
|
@@ -1745,9 +1745,14 @@ The most common failure mode is leaving cards IN_PROGRESS after merge. This crea
|
|
|
1745
1745
|
git -C "$MAIN" fetch origin --quiet
|
|
1746
1746
|
```
|
|
1747
1747
|
|
|
1748
|
-
2. **Parse `
|
|
1749
|
-
-
|
|
1750
|
-
|
|
1748
|
+
2. **Parse `mw-docs` sync markers** — scan the captured stdout from every `/mw` invocation in this batch (kept in the tracker under `## Worktree Merges`):
|
|
1749
|
+
- **`[SYNC-DEFERRED] main repo HEAD=<branch>`** (main repo HEAD ≠ develop) — surface via `AskUserQuestion`:
|
|
1750
|
+
- Question: `"Una o più merge worktree hanno deferito la sincronizzazione di local develop (main repo HEAD non era develop). Come riconcilio adesso?"`
|
|
1751
|
+
- Options: `[Ora HEAD è develop → ff-pull adesso]` / `[Lascia deferred (riconcilio io manualmente)]` / `[Mostra dettagli e fammi decidere]`.
|
|
1752
|
+
- **`[SYNC-NEEDS-DECISION] …`** (HEAD was develop but the ff was blocked by a **foreign** uncommitted file, or by a divergence/rebase conflict `/mw` would not auto-commit) — this is NEVER a passive note. Surface via `AskUserQuestion`:
|
|
1753
|
+
- Question: `"Il develop locale non si è sincronizzato: <dettaglio dal marker>. Come chiudo?"`
|
|
1754
|
+
- Options: `[Committa tu adesso (descrivi cosa)]` / `[Lo gestisco io — chiudi senza sync locale]` / `[Mostrami il diff e decidiamo]`.
|
|
1755
|
+
- **No marker** — `/mw` fast-forwarded (or auto-reconciled the framework telemetry log); nothing to parse.
|
|
1751
1756
|
|
|
1752
1757
|
3. **Clean-tree assertion (BLOCKING)**:
|
|
1753
1758
|
```bash
|
|
@@ -184,6 +184,45 @@ the state file (now on `develop` via the merge) shows `completed`.
|
|
|
184
184
|
|
|
185
185
|
Mark task 5 as `completed`.
|
|
186
186
|
|
|
187
|
+
### Step 7.5 — Workspace hygiene & finalization (BLOCKING — the run MUST conclude clean)
|
|
188
|
+
|
|
189
|
+
**Why this exists (v3.39.0).** A PRD run used to end by handing the user a list of
|
|
190
|
+
"azioni tue, non bloccanti" — an uncommitted file blocking the local `develop`
|
|
191
|
+
fast-forward, a remote branch left undeleted. That is a half-finished process.
|
|
192
|
+
`/prd` now closes the loop exactly like `/new` Phase 6c: **no residue is ever
|
|
193
|
+
surfaced as a passive manual TODO.** Every leftover is either auto-resolved or put
|
|
194
|
+
behind ONE explicit `AskUserQuestion` gate.
|
|
195
|
+
|
|
196
|
+
Scan the captured `mw-docs` stdout (the merge step above) for the structured
|
|
197
|
+
markers it can emit, then act:
|
|
198
|
+
|
|
199
|
+
1. **`[SYNC-NEEDS-DECISION] …`** — the local `develop` could not fast-forward and
|
|
200
|
+
the blocker is a **foreign** uncommitted file (one this run does not own), or a
|
|
201
|
+
genuine divergence/rebase conflict. Do NOT auto-commit foreign work. Raise ONE
|
|
202
|
+
`AskUserQuestion`:
|
|
203
|
+
- Question: `"Il develop locale non si è sincronizzato: <dettaglio dal marker>. Come chiudo?"`
|
|
204
|
+
- Options: `[Committa tu adesso (descrivi cosa)]` / `[Lo gestisco io — chiudi senza sync locale]` / `[Mostrami il diff e decidiamo]`.
|
|
205
|
+
Act on the answer in this turn. Never leave it as a printed note.
|
|
206
|
+
|
|
207
|
+
2. **`[SYNC-DEFERRED] …`** (main repo HEAD ≠ `develop`) — fetch already updated
|
|
208
|
+
`refs/remotes/origin/develop`. If the user's HEAD is now `develop`, run
|
|
209
|
+
`git -C "$MAIN" pull --ff-only origin develop`. Otherwise raise ONE
|
|
210
|
+
`AskUserQuestion` (`[ff-pull adesso]` / `[Lascio deferred, riconcilio io]`).
|
|
211
|
+
|
|
212
|
+
3. **No marker** — `mw-docs` already fast-forwarded (or auto-reconciled the
|
|
213
|
+
framework telemetry log). Nothing to do; the tree is clean.
|
|
214
|
+
|
|
215
|
+
4. **Remote feature branch** — `mw-docs` deletes the merged remote branch as
|
|
216
|
+
routine cleanup (see AGENTS.md § branch deletion: deleting an **already-merged**
|
|
217
|
+
feature branch is NOT the gated "branch deletion" that needs owner approval).
|
|
218
|
+
If for any reason the deletion was blocked, do NOT print "puoi cancellarlo a
|
|
219
|
+
mano": run `git push origin --delete <branch>` now, and only if THAT is denied
|
|
220
|
+
raise ONE `AskUserQuestion`.
|
|
221
|
+
|
|
222
|
+
**Gate:** `git -C "$MAIN" status --porcelain` for framework-owned paths is empty,
|
|
223
|
+
no `[SYNC-NEEDS-DECISION]` marker is left unhandled, and the merged remote branch
|
|
224
|
+
is gone (or its deletion is explicitly user-deferred).
|
|
225
|
+
|
|
187
226
|
### Final output
|
|
188
227
|
|
|
189
228
|
Print final summary:
|
|
@@ -193,6 +232,13 @@ Print final summary:
|
|
|
193
232
|
- Card IDs created
|
|
194
233
|
- Branch & merge strategy used
|
|
195
234
|
- PR number (if `strategy = pr`) or merge SHA (if `local-push`)
|
|
196
|
-
- Confirmation that the worktree was cleaned up
|
|
235
|
+
- Confirmation that the worktree was cleaned up AND the remote branch was deleted
|
|
236
|
+
|
|
237
|
+
**HARD RULE — no passive deferral.** The final summary MUST NOT contain a "azioni
|
|
238
|
+
tue / note non bloccanti / puoi farlo a mano" section. If something genuinely needs
|
|
239
|
+
the user, it was already raised as an `AskUserQuestion` in Step 7.5 and acted on —
|
|
240
|
+
it does not reappear here as a TODO. A run that prints "il develop locale non si è
|
|
241
|
+
fast-forwardato, gestisci tu il file e poi pulla" has FAILED Step 7.5 — go back and
|
|
242
|
+
resolve it before printing the summary.
|
|
197
243
|
|
|
198
244
|
Display completed Progress Bar.
|
|
@@ -865,8 +865,44 @@ PR_NUMBER=""
|
|
|
865
865
|
# HEAD alone and they'll pull next time.
|
|
866
866
|
CURRENT_BRANCH=$(git -C "$MAIN" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
867
867
|
if [ "$CURRENT_BRANCH" = "develop" ]; then
|
|
868
|
-
git -C "$MAIN" pull --ff-only origin develop
|
|
869
|
-
echo "
|
|
868
|
+
if git -C "$MAIN" pull --ff-only origin develop 2>/dev/null; then
|
|
869
|
+
echo "✅ Main repo develop fast-forwarded to origin/develop."
|
|
870
|
+
else
|
|
871
|
+
# FF blocked. NEVER leave this as a passive "Leaving as-is" TODO for the user
|
|
872
|
+
# (v3.39.0 — the finalizer MUST conclude). The cause is almost always an
|
|
873
|
+
# uncommitted append to the framework-owned telemetry log left by a prior run.
|
|
874
|
+
# Partition the dirty tree:
|
|
875
|
+
# - framework-owned artifact (docs/metrics/skill-runs.jsonl) → auto-reconcile
|
|
876
|
+
# (commit + rebase) so the ff completes with zero data loss;
|
|
877
|
+
# - ANY foreign file → emit a decision marker the orchestrator MUST convert
|
|
878
|
+
# into ONE explicit user gate. Never auto-commit work this run did not own.
|
|
879
|
+
DIRTY=$(git -C "$MAIN" status --porcelain --untracked-files=no | sed 's/^...//')
|
|
880
|
+
FOREIGN=""
|
|
881
|
+
OWNED=""
|
|
882
|
+
for f in $DIRTY; do
|
|
883
|
+
case "$f" in
|
|
884
|
+
docs/metrics/skill-runs.jsonl) OWNED="$OWNED $f" ;;
|
|
885
|
+
*) FOREIGN="$FOREIGN $f" ;;
|
|
886
|
+
esac
|
|
887
|
+
done
|
|
888
|
+
if [ -n "$FOREIGN" ]; then
|
|
889
|
+
echo "[SYNC-NEEDS-DECISION] main repo develop cannot fast-forward; foreign uncommitted files:${FOREIGN} — orchestrator MUST raise ONE explicit user gate (commit / user-handles), never a passive note."
|
|
890
|
+
elif [ -n "$OWNED" ]; then
|
|
891
|
+
# Only framework-owned telemetry is dirty → reconcile autonomously, lossless.
|
|
892
|
+
git -C "$MAIN" add docs/metrics/skill-runs.jsonl
|
|
893
|
+
git -C "$MAIN" commit -m "chore(metrics): reconcile skill-runs telemetry before develop sync" --quiet
|
|
894
|
+
if git -C "$MAIN" pull --rebase origin develop 2>/dev/null; then
|
|
895
|
+
git -C "$MAIN" push origin develop 2>/dev/null \
|
|
896
|
+
&& echo "✅ Reconciled stale metrics log + synced develop to origin." \
|
|
897
|
+
|| echo "✅ Reconciled stale metrics log (local develop 1 commit ahead; syncs on next push). Tree clean."
|
|
898
|
+
else
|
|
899
|
+
git -C "$MAIN" rebase --abort 2>/dev/null || true
|
|
900
|
+
echo "[SYNC-NEEDS-DECISION] metrics rebase conflict on develop — orchestrator MUST raise ONE explicit user gate."
|
|
901
|
+
fi
|
|
902
|
+
else
|
|
903
|
+
echo "[SYNC-NEEDS-DECISION] main repo develop cannot fast-forward and the working tree is clean (diverged?) — orchestrator MUST raise ONE explicit user gate."
|
|
904
|
+
fi
|
|
905
|
+
fi
|
|
870
906
|
else
|
|
871
907
|
echo "ℹ️ Main repo HEAD is '$CURRENT_BRANCH' — not switching. Next manual `git pull` on develop will sync."
|
|
872
908
|
git -C "$MAIN" fetch origin develop --quiet
|
|
@@ -905,8 +941,17 @@ git branch -d "$BRANCH"
|
|
|
905
941
|
```
|
|
906
942
|
|
|
907
943
|
```bash
|
|
908
|
-
# 3. Delete the remote branch
|
|
909
|
-
|
|
944
|
+
# 3. Delete the remote branch. The branch is ALREADY MERGED into develop at this
|
|
945
|
+
# point, so this is routine cleanup — NOT the gated "branch deletion" that needs
|
|
946
|
+
# owner approval (see AGENTS.md § branch deletion). Report the outcome; never
|
|
947
|
+
# degrade a failure into a passive "puoi cancellarlo a mano" note handed to the user.
|
|
948
|
+
if git push origin --delete "$BRANCH" 2>/dev/null; then
|
|
949
|
+
echo "✅ Remote branch '$BRANCH' deleted (merged → routine cleanup)."
|
|
950
|
+
else
|
|
951
|
+
echo "ℹ️ Remote branch '$BRANCH' not deleted (already gone, or the deletion was denied)."
|
|
952
|
+
echo " If denied: this is a merged branch — retry the delete; only if it is STILL"
|
|
953
|
+
echo " denied must the orchestrator raise ONE explicit user gate, never a passive TODO."
|
|
954
|
+
fi
|
|
910
955
|
```
|
|
911
956
|
|
|
912
957
|
```bash
|
|
@@ -923,12 +968,15 @@ Remove the entry from `.worktrees/registry.json`.
|
|
|
923
968
|
```
|
|
924
969
|
Merge complete:
|
|
925
970
|
Card: <CARD-ID>
|
|
926
|
-
Branch: <BRANCH> (deleted on remote
|
|
971
|
+
Branch: <BRANCH> (deleted on remote — merged branch deletion is routine cleanup, never gated)
|
|
927
972
|
Strategy: <pr | local-push>
|
|
928
973
|
PR: #<PR_NUMBER> merged via `gh pr merge` ← only in `pr` strategy
|
|
929
974
|
Push: fast-forward to origin/develop ← only in `local-push` strategy
|
|
930
975
|
Worktree: <WORKTREE_PATH> (removed)
|
|
931
|
-
develop: remote up to date; local main-repo synced
|
|
976
|
+
develop: remote up to date; local main-repo synced (auto-reconciled framework
|
|
977
|
+
telemetry if it blocked the ff). Any [SYNC-NEEDS-DECISION] /
|
|
978
|
+
[SYNC-DEFERRED] marker above is for the orchestrator to gate on —
|
|
979
|
+
NOT a residue to hand the user as a manual TODO.
|
|
932
980
|
```
|
|
933
981
|
|
|
934
982
|
---
|
package/framework/AGENTS.md
CHANGED
|
@@ -104,9 +104,9 @@ Conflict steps (must follow in order):
|
|
|
104
104
|
- MUST use commit format `[FEAT-XXX] Brief description` or adapt to your project's convention; keep commits small/traceable.
|
|
105
105
|
- MUST NOT commit without updated docs or with failing lint/type checks. Full build is required only before opening a PR, not before every commit.
|
|
106
106
|
- MUST pre-sync: `git fetch origin`, clean status, confirm branch; use `git pull --ff-only` unless approved.
|
|
107
|
-
- MUST get owner approval before force push/reset
|
|
107
|
+
- MUST get owner approval before force push/reset, and before deleting an **unmerged** branch; create a safety tag `backup/<YYYYMMDD>-<reason>`. Deleting a feature branch that is **already merged** into `develop` is routine cleanup (it carries no unmerged work) and does NOT require a separate approval — the merge skill deletes it automatically.
|
|
108
108
|
- MUST NEVER push directly to `main`; all changes reach `main` via PR (release from `develop` or hotfix merge). Pre-push hook enforces this.
|
|
109
|
-
- MUST push working branch and keep `main` merge owner-controlled;
|
|
109
|
+
- MUST push working branch and keep `main` merge owner-controlled; the merge skill prunes a feature branch's own remote ref on successful merge into `develop` (routine), but pruning OTHER remote branches happens only when instructed.
|
|
110
110
|
- MUST run testing gates before DONE: run tests (if exist), run build, and CI checks on PR; manual validation is REQUIRED for local mode and OPTIONAL for cloud mode.
|
|
111
111
|
- MUST pass pre-commit hooks (linting, type checking, markdown lint, build); bypass (`--no-verify`) only for documented emergencies.
|
|
112
112
|
- MUST use API versioning for breaking changes: create new version, deprecate old with appropriate headers, minimum sunset period; see project-specific API migration docs.
|