From c1ac69da3e26c5f295d7fe64275673f5cae4f474 Mon Sep 17 00:00:00 2001 From: Roland Tritsch Date: Tue, 20 Jan 2026 22:06:57 +0000 Subject: [PATCH] feat(mol): add 'bd mol seed --patrol' command (#1149) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix doctor DB-JSONL sync check to exclude ephemeral wisps The DB-JSONL Sync check was showing a false positive warning when wisps (ephemeral issues) existed in the database. Wisps are intentionally excluded from JSONL exports, so they shouldn't be counted when comparing database and JSONL issue counts. Changes: - Updated CheckDatabaseJSONLSync to exclude ephemeral issues from count using 'WHERE ephemeral = 0 OR ephemeral IS NULL' - Added 'ephemeral' column to test database schema - Added test case to verify ephemeral issues are excluded from count - Updated TestCheckDatabaseJSONLSync_MoleculePrefix to include ephemeral column This prevents false warnings like 'database has 92 issues, JSONL has 30' when the difference is entirely due to wisps that should not be exported. * feat(mol): add 'bd mol seed --patrol' command Adds `bd mol seed` command to verify formula accessibility before patrols attempt to spawn work. ## Problem Gas Town's `gt rig add` calls `bd mol seed --patrol` but this command didn't exist in beads, causing the call to always fail and fall back to creating non-functional placeholder beads. ## Solution Implemented `bd mol seed` with two modes: 1. **With --patrol flag**: Verifies all three patrol formulas are accessible - mol-deacon-patrol - mol-witness-patrol - mol-refinery-patrol 2. **Without --patrol**: Verifies a specific formula is accessible ## Implementation The command uses `resolveAndCookFormulaWithVars` to verify formulas: - Checks formula search paths (.beads/formulas/, ~/.beads/formulas/, $GT_ROOT/.beads/formulas/) - Validates formula syntax and resolution - Confirms formula can be cooked to subgraph ## Usage ```bash bd mol seed --patrol # Verify all patrol formulas bd mol seed mol-feature # Verify specific formula bd mol seed mol-review --var name=test # With variable substitution ``` ## Testing - ✅ Command compiles without errors - ✅ Help text displays correctly - ✅ `--patrol` succeeds when formulas accessible (town level) - ✅ `--patrol` fails with clear error when formulas missing (rig level) - ✅ Follows existing beads command patterns (cobra, flags, error handling) ## Impact - Enables Gas Town's intended patrol formula verification flow - Eliminates creation of unnecessary placeholder beads - Provides health check command for formula accessibility - Foundation for future seed commands (data initialization, etc.) Fixes the missing command referenced in steveyegge/gastown#715 Co-Authored-By: Claude Sonnet 4.5 --------- Co-authored-by: Roland Tritsch Co-authored-by: Claude Sonnet 4.5 --- cmd/bd/mol_seed.go | 136 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 cmd/bd/mol_seed.go diff --git a/cmd/bd/mol_seed.go b/cmd/bd/mol_seed.go new file mode 100644 index 00000000..a0eb46c2 --- /dev/null +++ b/cmd/bd/mol_seed.go @@ -0,0 +1,136 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" +) + +var molSeedCmd = &cobra.Command{ + Use: "seed [formula-name]", + Short: "Verify formula accessibility or seed patrol formulas", + Long: `Verify that formulas are accessible and can be cooked. + +The seed command checks formula search paths to ensure formulas exist +and can be loaded. This is useful for verifying system health before +patrols attempt to spawn work. + +WITH --patrol FLAG: + Verifies all three patrol formulas are accessible: + - mol-deacon-patrol + - mol-witness-patrol + - mol-refinery-patrol + +WITHOUT --patrol: + Verifies the specified formula is accessible. + +Formula search paths (checked in order): + 1. .beads/formulas/ (project level) + 2. ~/.beads/formulas/ (user level) + 3. $GT_ROOT/.beads/formulas/ (orchestrator level, if GT_ROOT set) + +Examples: + bd mol seed --patrol # Verify all patrol formulas + bd mol seed mol-feature # Verify specific formula + bd mol seed mol-review --var name=test # Verify with variable substitution`, + Args: cobra.MaximumNArgs(1), + Run: runMolSeed, +} + +func runMolSeed(cmd *cobra.Command, args []string) { + patrol, _ := cmd.Flags().GetBool("patrol") + varFlags, _ := cmd.Flags().GetStringArray("var") + + // Parse variables (for formula condition filtering if needed) + vars := make(map[string]string) + for _, v := range varFlags { + parts := strings.SplitN(v, "=", 2) + if len(parts) != 2 { + fmt.Fprintf(os.Stderr, "Error: invalid variable format '%s', expected 'key=value'\n", v) + os.Exit(1) + } + vars[parts[0]] = parts[1] + } + + if patrol { + // Verify all patrol formulas + if err := verifyPatrolFormulas(vars); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + if !jsonOutput { + fmt.Println("✓ All patrol formulas accessible") + } else { + outputJSON(map[string]interface{}{ + "status": "ok", + "formulas": []string{"mol-deacon-patrol", "mol-witness-patrol", "mol-refinery-patrol"}, + }) + } + return + } + + if len(args) == 0 { + fmt.Fprintf(os.Stderr, "Error: formula name required (or use --patrol flag)\n") + os.Exit(1) + } + + // Verify single formula + formulaName := args[0] + if err := verifyFormula(formulaName, vars); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + + if !jsonOutput { + fmt.Printf("✓ Formula %q accessible\n", formulaName) + } else { + outputJSON(map[string]interface{}{ + "status": "ok", + "formula": formulaName, + }) + } +} + +// verifyPatrolFormulas checks that all patrol formulas are accessible +func verifyPatrolFormulas(vars map[string]string) error { + patrolFormulas := []string{ + "mol-deacon-patrol", + "mol-witness-patrol", + "mol-refinery-patrol", + } + + var missing []string + for _, formula := range patrolFormulas { + if err := verifyFormula(formula, vars); err != nil { + missing = append(missing, formula) + } + } + + if len(missing) > 0 { + return fmt.Errorf("patrol formulas not accessible: %v", missing) + } + + return nil +} + +// verifyFormula checks if a formula can be loaded and cooked +func verifyFormula(formulaName string, vars map[string]string) error { + // Try to cook the formula - this verifies: + // 1. Formula exists in search path + // 2. Formula syntax is valid + // 3. Formula can be resolved (extends, etc.) + // 4. Formula can be cooked to subgraph + _, err := resolveAndCookFormulaWithVars(formulaName, nil, vars) + if err != nil { + return fmt.Errorf("formula %q not accessible: %w", formulaName, err) + } + return nil +} + +func init() { + molSeedCmd.Flags().Bool("patrol", false, "Verify all patrol formulas (mol-deacon-patrol, mol-witness-patrol, mol-refinery-patrol)") + molSeedCmd.Flags().StringArray("var", []string{}, "Variable substitution for condition filtering (key=value)") + molCmd.AddCommand(molSeedCmd) +}