Feat v0.3.0 workflow schema (#14)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Successful in 2m23s
CI/CD / test-sqlite (push) Successful in 2m42s
CI/CD / build-and-deploy (push) Successful in 1m28s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #14.
This commit is contained in:
2026-03-27 17:52:29 +00:00
committed by xcaliber
parent 8580e1d93e
commit 965885a8f7
16 changed files with 414 additions and 161 deletions

View File

@@ -8,13 +8,13 @@ import (
"switchboard-core/models"
)
// ── Conditional Routing Engine (v0.35.0) ────
// ── Conditional Routing Engine ───────────────
//
// Evaluates transition_rules.conditions[] against accumulated stage_data
// to determine which stage to advance to. Falls back to ordinal + 1
// when no conditions are defined or none match.
// Evaluates branch_rules[] against accumulated stage_data to determine
// which stage to advance to. Falls back to ordinal + 1 when no rules
// are defined or none match.
// Condition is a single routing condition within transition_rules.
// Condition is a single routing rule within branch_rules.
type Condition struct {
Field string `json:"field"`
Op string `json:"op"`
@@ -22,15 +22,21 @@ type Condition struct {
TargetStage string `json:"target_stage"` // stage name or ordinal as string
}
// TransitionRulesWithConditions extends the existing transition_rules JSON.
type TransitionRulesWithConditions struct {
AutoAssign string `json:"auto_assign,omitempty"`
Conditions []Condition `json:"conditions,omitempty"`
// StageConfig holds non-routing config from stage_config JSON.
type StageConfig struct {
AutoAssign string `json:"auto_assign,omitempty"`
OnAdvance *OnAdvanceReference `json:"on_advance,omitempty"`
}
// ResolveNextStage evaluates conditions from the current stage's transition_rules
// against accumulated stageData. Returns the target stage ordinal.
// Falls back to currentStage + 1 if no conditions match or none are defined.
// OnAdvanceReference points to a Starlark hook for on_advance processing.
type OnAdvanceReference struct {
PackageID string `json:"package_id"`
EntryPoint string `json:"entry_point"`
}
// ResolveNextStage evaluates branch_rules from the current stage against
// accumulated stageData. Returns the target stage ordinal.
// Falls back to currentStage + 1 if no rules match or none are defined.
func ResolveNextStage(stages []models.WorkflowStage, currentStage int, stageData json.RawMessage) (int, error) {
if currentStage < 0 || currentStage >= len(stages) {
return currentStage + 1, nil
@@ -38,12 +44,12 @@ func ResolveNextStage(stages []models.WorkflowStage, currentStage int, stageData
stage := stages[currentStage]
var rules TransitionRulesWithConditions
if len(stage.TransitionRules) > 0 {
_ = json.Unmarshal(stage.TransitionRules, &rules)
var rules []Condition
if len(stage.BranchRules) > 0 && string(stage.BranchRules) != "[]" {
_ = json.Unmarshal(stage.BranchRules, &rules)
}
if len(rules.Conditions) == 0 {
if len(rules) == 0 {
return currentStage + 1, nil
}
@@ -55,7 +61,7 @@ func ResolveNextStage(stages []models.WorkflowStage, currentStage int, stageData
data = map[string]any{}
}
for _, cond := range rules.Conditions {
for _, cond := range rules {
if evaluateCondition(cond, data) {
target, err := resolveTarget(stages, cond.TargetStage)
if err != nil {