{"record":{"id":"5ca1f2154c04ce77","repo":"gastownhall/beads","slug":"applying-branches-w","errorCode":null,"errorMessage":"applying branches: %w","messagePattern":"applying branches: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/controlflow.go","lineNumber":567,"sourceCode":"// 3. Gates (add condition labels)\n//\n// Returns a new steps slice. The original steps slice is not modified.\nfunc ApplyControlFlow(steps []*Step, compose *ComposeRules) ([]*Step, error) {\n\tvar err error\n\n\t// Apply loops first (expands steps) - ApplyLoops already returns new slice\n\tsteps, err = ApplyLoops(steps)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"applying loops: %w\", err)\n\t}\n\n\t// Build stepMap once for branches and gates\n\t// No need to clone here since ApplyLoops already returned a new slice\n\tstepMap := buildStepMap(steps)\n\n\t// Apply branches (wires dependencies)\n\tif err := applyBranchesWithMap(stepMap, compose); err != nil {\n\t\treturn nil, fmt.Errorf(\"applying branches: %w\", err)\n\t}\n\n\t// Apply gates (adds labels)\n\tif err := applyGatesWithMap(stepMap, compose); err != nil {\n\t\treturn nil, fmt.Errorf(\"applying gates: %w\", err)\n\t}\n\n\treturn steps, nil\n}\n\n// cloneStepDeep creates a deep copy of a step including children.\nfunc cloneStepDeep(s *Step) *Step {\n\tclone := cloneStep(s)\n\n\tif len(s.Children) > 0 {\n\t\tclone.Children = make([]*Step, len(s.Children))\n\t\tfor i, child := range s.Children {\n\t\t\tclone.Children[i] = cloneStepDeep(child)","sourceCodeStart":549,"sourceCodeEnd":585,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/controlflow.go#L549-L585","documentation":"ApplyControlFlow wraps failures from applyBranchesWithMap with 'applying branches: %w'. Branch rules wire fork-join dependency patterns: all branch steps depend on the 'from' step and the 'join' step depends on all branch steps. This error means a branch rule is missing a required field (from, steps, join) or references a step ID that does not exist in the step map.","triggerScenarios":"Calling ApplyControlFlow(steps, compose) where a compose.Branch entry has empty From/Join/Steps, or where From, Join, or any Steps entry names a step ID absent from the formula (checked via stepMap built after loop expansion).","commonSituations":"Typos in branch from/join/step IDs in formula compose config; a branch rule pointing at a step created or renamed by a loop expansion under different IDs; deleting a step without updating the branch rule.","solutions":["Read the wrapped inner error — it says exactly which field is missing or which step ID was not found","Verify every branch From, Join, and Steps ID exists in the formula after loop expansion (expansion can rename/replace steps)","Run ApplyLoops first and inspect the expanded step IDs to confirm branch targets survive expansion","Correct the branch rule IDs or remove the stale rule in the compose section"],"exampleFix":"// before\nbranches:\n  - from: plan\n    steps: [build-api, build-web]\n    join: intergrate\n// after\nbranches:\n  - from: plan\n    steps: [build-api, build-web]\n    join: integrate","handlingStrategy":"validation","validationCode":"for _, b := range compose.Branch {\n\tif b.From == \"\" || b.Join == \"\" || len(b.Steps) == 0 {\n\t\treturn fmt.Errorf(\"branch rule incomplete: from=%q join=%q steps=%d\", b.From, b.Join, len(b.Steps))\n\t}\n\tids := buildStepMap(steps) // includes nested children\n\tfor _, id := range append([]string{b.From, b.Join}, b.Steps...) {\n\t\tif _, ok := ids[id]; !ok {\n\t\t\treturn fmt.Errorf(\"branch references missing step %q\", id)\n\t\t}\n\t}\n}","typeGuard":null,"tryCatchPattern":"out, err := ApplyControlFlow(steps, compose)\nif err != nil {\n\tif strings.Contains(err.Error(), \"applying branches\") {\n\t\treturn fmt.Errorf(\"invalid branch rule in compose: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Validate branch from/join/steps IDs against the formula's step list before applying","Run loop expansion first when authoring, since branch targets may be expansion products","Test every formula's compose rules with ApplyBranches in CI","Delete stale branch rules when removing steps"],"tags":["go","formula","control-flow","branch-dependencies"],"backgroundTag":"compose-rule-target-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}