From 93d7cffc68117722cf9bf4bc19c857722bc17d58 Mon Sep 17 00:00:00 2001 From: "Toast (gastown)" Date: Tue, 24 Mar 2026 20:05:44 +0000 Subject: [PATCH] fix: move rootOnly override before dryRun check in runWispCreate Fixes steveyegge/beads#2725. The --dry-run early return was executing before the rootOnly override logic, causing dry-run to report all N issues would be created while the actual run only creates 1 (root). - Move rootOnly override block above the dryRun check so both paths see the same rootOnly value - Update dry-run output to show '1 issue (root only)' with a note explaining how many child steps were skipped and how to enable them via pour=true in the formula - For pour=true formulas, dry-run still reports all issues as before --- cmd/bd/wisp.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/cmd/bd/wisp.go b/cmd/bd/wisp.go index ed252928f3..fa7849f41a 100644 --- a/cmd/bd/wisp.go +++ b/cmd/bd/wisp.go @@ -243,23 +243,35 @@ func runWispCreate(cmd *cobra.Command, args []string) { ) } + // Wisps are vapor (ephemeral) by default — only create the root issue. + // Materializing child step issues is the "pour" path (bd pour), not wisps. + // Formulas that explicitly set pour=true get children even as wisps. + if !rootOnly && subgraph != nil && !subgraph.Pour { + rootOnly = true + } + if dryRun { - fmt.Printf("\nDry run: would create wisp with %d issues from proto %s\n\n", len(subgraph.Issues), protoID) + if rootOnly { + skipped := len(subgraph.Issues) - 1 + fmt.Printf("\nDry run: would create wisp with 1 issue (root only) from proto %s\n", protoID) + if skipped > 0 { + fmt.Printf(" Note: %d child step(s) skipped — set pour=true in formula to materialize them\n", skipped) + } + } else { + fmt.Printf("\nDry run: would create wisp with %d issues from proto %s\n\n", len(subgraph.Issues), protoID) + } fmt.Printf("Storage: main database (ephemeral=true, not synced via git)\n\n") - for _, issue := range subgraph.Issues { + issuesToShow := subgraph.Issues + if rootOnly && len(issuesToShow) > 0 { + issuesToShow = issuesToShow[:1] + } + for _, issue := range issuesToShow { newTitle := substituteVariables(issue.Title, vars) fmt.Printf(" - %s (from %s)\n", newTitle, issue.ID) } return } - // Wisps are vapor (ephemeral) by default — only create the root issue. - // Materializing child step issues is the "pour" path (bd pour), not wisps. - // Formulas that explicitly set pour=true get children even as wisps. - if !rootOnly && subgraph != nil && !subgraph.Pour { - rootOnly = true - } - // Spawn as ephemeral in main database (Ephemeral=true, not synced via git) // Use wisp prefix for distinct visual recognition (see types.IDPrefixWisp) result, err := spawnMoleculeWithOptions(ctx, store, subgraph, CloneOptions{