feat: implement Step.Condition evaluation in bd cook (bd-7zka.1)
Add compile-time step filtering based on formula variables:
- New EvaluateStepCondition function for {{var}} truthy and equality checks
- FilterStepsByCondition to exclude steps based on conditions
- Integration into pour, wisp, and mol bond commands
- Supports: {{var}}, {{var}} == value, {{var}} != value
Steps with conditions that evaluate to false are excluded from the
cooked formula, along with their children.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
82611834df
commit
ee34a74e90
@@ -574,6 +574,13 @@ func collectSteps(steps []*formula.Step, parentID string,
|
||||
// and returns an in-memory TemplateSubgraph ready for instantiation.
|
||||
// This is the main entry point for ephemeral proto cooking.
|
||||
func resolveAndCookFormula(formulaName string, searchPaths []string) (*TemplateSubgraph, error) {
|
||||
return resolveAndCookFormulaWithVars(formulaName, searchPaths, nil)
|
||||
}
|
||||
|
||||
// resolveAndCookFormulaWithVars loads a formula and optionally filters steps by condition.
|
||||
// If conditionVars is provided, steps with conditions that evaluate to false are excluded.
|
||||
// Pass nil for conditionVars to include all steps (condition filtering skipped).
|
||||
func resolveAndCookFormulaWithVars(formulaName string, searchPaths []string, conditionVars map[string]string) (*TemplateSubgraph, error) {
|
||||
// Create parser with search paths
|
||||
parser := formula.NewParser(searchPaths...)
|
||||
|
||||
@@ -633,6 +640,27 @@ func resolveAndCookFormula(formulaName string, searchPaths []string) (*TemplateS
|
||||
}
|
||||
}
|
||||
|
||||
// Apply step condition filtering if vars provided (bd-7zka.1)
|
||||
// This filters out steps whose conditions evaluate to false
|
||||
if conditionVars != nil {
|
||||
// Merge with formula defaults for complete evaluation
|
||||
mergedVars := make(map[string]string)
|
||||
for name, def := range resolved.Vars {
|
||||
if def != nil && def.Default != "" {
|
||||
mergedVars[name] = def.Default
|
||||
}
|
||||
}
|
||||
for k, v := range conditionVars {
|
||||
mergedVars[k] = v
|
||||
}
|
||||
|
||||
filteredSteps, err := formula.FilterStepsByCondition(resolved.Steps, mergedVars)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("filtering steps by condition: %w", err)
|
||||
}
|
||||
resolved.Steps = filteredSteps
|
||||
}
|
||||
|
||||
// Cook to in-memory subgraph, including variable definitions for default handling
|
||||
return cookFormulaToSubgraphWithVars(resolved, resolved.Formula, resolved.Vars)
|
||||
}
|
||||
|
||||
@@ -208,12 +208,13 @@ func runMolBond(cmd *cobra.Command, args []string) {
|
||||
|
||||
// Resolve both operands - can be issue IDs or formula names
|
||||
// Formula names are cooked inline to in-memory subgraphs
|
||||
subgraphA, cookedA, err := resolveOrCookToSubgraph(ctx, store, args[0])
|
||||
// Pass vars for step condition filtering (bd-7zka.1)
|
||||
subgraphA, cookedA, err := resolveOrCookToSubgraph(ctx, store, args[0], vars)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
subgraphB, cookedB, err := resolveOrCookToSubgraph(ctx, store, args[1])
|
||||
subgraphB, cookedB, err := resolveOrCookToSubgraph(ctx, store, args[1], vars)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
@@ -569,8 +570,9 @@ func resolveOrDescribe(ctx context.Context, s storage.Storage, operand string) (
|
||||
// If it's an issue, loads the subgraph from DB. If it's a formula, cooks inline to subgraph.
|
||||
// Returns the subgraph, whether it was cooked from formula, and any error.
|
||||
//
|
||||
// The vars parameter is used for step condition filtering (bd-7zka.1).
|
||||
// This implements gt-4v1eo: formulas are cooked to in-memory subgraphs (no DB storage).
|
||||
func resolveOrCookToSubgraph(ctx context.Context, s storage.Storage, operand string) (*TemplateSubgraph, bool, error) {
|
||||
func resolveOrCookToSubgraph(ctx context.Context, s storage.Storage, operand string, vars map[string]string) (*TemplateSubgraph, bool, error) {
|
||||
// First, try to resolve as an existing issue
|
||||
id, err := utils.ResolvePartialID(ctx, s, operand)
|
||||
if err == nil {
|
||||
@@ -599,7 +601,8 @@ func resolveOrCookToSubgraph(ctx context.Context, s storage.Storage, operand str
|
||||
}
|
||||
|
||||
// Try to cook formula inline to in-memory subgraph
|
||||
subgraph, err := resolveAndCookFormula(operand, nil)
|
||||
// Pass vars for step condition filtering (bd-7zka.1)
|
||||
subgraph, err := resolveAndCookFormulaWithVars(operand, nil, vars)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("'%s' not found as issue or formula: %w", operand, err)
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ func runPour(cmd *cobra.Command, args []string) {
|
||||
|
||||
// Try to cook formula inline (gt-4v1eo: ephemeral protos)
|
||||
// This works for any valid formula name, not just "mol-" prefixed ones
|
||||
sg, err := resolveAndCookFormula(args[0], nil)
|
||||
// Pass vars for step condition filtering (bd-7zka.1)
|
||||
sg, err := resolveAndCookFormulaWithVars(args[0], nil, vars)
|
||||
if err == nil {
|
||||
subgraph = sg
|
||||
protoID = sg.Root.ID
|
||||
|
||||
@@ -167,7 +167,8 @@ func runWispCreate(cmd *cobra.Command, args []string) {
|
||||
|
||||
// Try to cook formula inline (ephemeral protos)
|
||||
// This works for any valid formula name, not just "mol-" prefixed ones
|
||||
sg, err := resolveAndCookFormula(args[0], nil)
|
||||
// Pass vars for step condition filtering (bd-7zka.1)
|
||||
sg, err := resolveAndCookFormulaWithVars(args[0], nil, vars)
|
||||
if err == nil {
|
||||
subgraph = sg
|
||||
protoID = sg.Root.ID
|
||||
|
||||
Reference in New Issue
Block a user