package config_test import ( "os" "path/filepath" "strings" "testing" "iop/packages/go/config" ) // TestLoadEdgeExecutionPresetCatalog verifies that valid direct and light preset // shapes decode, normalize, and survive LoadEdge alongside existing provider- // only fixtures. func TestLoadEdgeExecutionPresetCatalog(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") // Direct preset: no downstream stages, no options. directYAML := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "direct-default" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` t.Run("direct preset loads", func(t *testing.T) { if err := os.WriteFile(f, []byte(directYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.ExecutionPresets) != 1 { t.Fatalf("expected 1 preset, got %d", len(cfg.ExecutionPresets)) } p := cfg.ExecutionPresets[0] if p.ID != "direct-default" { t.Errorf("preset id = %q, want %q", p.ID, "direct-default") } if p.Selector.Model != "model-a" { t.Errorf("selector model = %q, want %q", p.Selector.Model, "model-a") } if len(p.AllowedModes) != 1 || p.AllowedModes[0] != "direct" { t.Errorf("allowed_modes = %v, want [direct]", p.AllowedModes) } if len(p.Routes["direct"].Stages) != 0 { t.Errorf("expected 0 route stages for direct, got %d", len(p.Routes["direct"].Stages)) } }) // Route key with surrounding whitespace normalizes. whitespaceRouteYAML := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "whitespace-route" selector: model: "model-a" allowed_modes: - "direct" routes: " direct ": stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` t.Run("route key with surrounding whitespace normalizes", func(t *testing.T) { if err := os.WriteFile(f, []byte(whitespaceRouteYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.ExecutionPresets) != 1 { t.Fatalf("expected 1 preset, got %d", len(cfg.ExecutionPresets)) } p := cfg.ExecutionPresets[0] if _, ok := p.Routes["direct"]; !ok { t.Errorf("expected route key 'direct' after normalization, got routes %v", p.Routes) } if _, rawExists := p.Routes[" direct "]; rawExists { t.Errorf("raw un-trimmed route key ' direct ' should not remain in routes") } }) // Hybrid multi-mode preset (direct and light). hybridYAML := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "hybrid-preset" selector: model: "model-a" options: temperature: 0.2 allowed_modes: - "direct" - "light" routes: direct: stages: [] light: stages: - role: "local" model: "model-a" options: timeout_ms: "30000" - role: "review" model: "model-b" options: max_retries: "2" workspace_tools: - name: "standard-fs" operations: " prepare ": tool_name: "mkdir_p" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" read: tool_name: "read_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "write_file" creates_parents: false schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "delete_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` t.Run("hybrid multi-mode preset loads with workspace tools", func(t *testing.T) { if err := os.WriteFile(f, []byte(hybridYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.ExecutionPresets) != 1 { t.Fatalf("expected 1 preset, got %d", len(cfg.ExecutionPresets)) } p := cfg.ExecutionPresets[0] if p.ID != "hybrid-preset" { t.Errorf("preset id = %q, want %q", p.ID, "hybrid-preset") } if len(p.AllowedModes) != 2 || p.AllowedModes[0] != "direct" || p.AllowedModes[1] != "light" { t.Errorf("allowed_modes = %v, want [direct, light]", p.AllowedModes) } if len(p.Routes["light"].Stages) != 2 { t.Fatalf("expected 2 route stages for light, got %d", len(p.Routes["light"].Stages)) } if p.Routes["light"].Stages[0].Role != "local" || p.Routes["light"].Stages[0].Model != "model-a" { t.Errorf("light stage 0 = %+v", p.Routes["light"].Stages[0]) } if p.Routes["light"].Stages[1].Role != "review" || p.Routes["light"].Stages[1].Model != "model-b" { t.Errorf("light stage 1 = %+v", p.Routes["light"].Stages[1]) } if len(p.WorkspaceTools) != 1 { t.Fatalf("expected 1 workspace tool alternative, got %d", len(p.WorkspaceTools)) } wt := p.WorkspaceTools[0] if wt.Name != "standard-fs" { t.Errorf("workspace tool name = %q, want standard-fs", wt.Name) } if wt.Operations["write"].ToolName != "write_file" { t.Errorf("write operation tool_name = %q, want write_file", wt.Operations["write"].ToolName) } prepOp, hasPrep := wt.Operations["prepare"] if !hasPrep || prepOp.ToolName != "mkdir_p" { t.Errorf("prepare operation failed normalized key lookup, got %+v", prepOp) } if prepOp.SchemaMatcher == nil || prepOp.ArgumentMap == nil || prepOp.ResultMatcher == nil { t.Errorf("prepare operation missing matchers/mappings, got %+v", prepOp) } }) // Multiple presets with mixed modes. multiYAML := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "fast-path" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] - id: "review-path" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "tee" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "rm" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` t.Run("multiple presets with mixed modes", func(t *testing.T) { if err := os.WriteFile(f, []byte(multiYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.ExecutionPresets) != 2 { t.Fatalf("expected 2 presets, got %d", len(cfg.ExecutionPresets)) } byID := map[string]config.ExecutionPreset{} for _, p := range cfg.ExecutionPresets { byID[p.ID] = p } if _, ok := byID["fast-path"]; !ok { t.Fatal("expected fast-path preset") } if _, ok := byID["review-path"]; !ok { t.Fatal("expected review-path preset") } }) // Empty execution_presets should load fine. emptyYAML := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` t.Run("no presets defined loads fine", func(t *testing.T) { if err := os.WriteFile(f, []byte(emptyYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } }) // Existing provider-only fixtures must remain compatible. providerOnlyYAML := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" providers: vllm-gpu: "nvidia/Qwen3.6-35B" nodes: - id: "node-gpu-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "nvidia/Qwen3.6-35B" capacity: 4 ` t.Run("provider-only config remains compatible", func(t *testing.T) { if err := os.WriteFile(f, []byte(providerOnlyYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } }) } // TestLoadEdgeExecutionPresetRejectsInvalidShape verifies that invalid ids, // routes, options, binding shapes, dangling references, and unsupported handlers fail closed. func TestLoadEdgeExecutionPresetRejectsInvalidShape(t *testing.T) { t.Run("approved top-level list required map shape rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" execution_presets: presets: - id: "bad-shape" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for map shape execution_presets") } }) t.Run("unknown preset field rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "unknown-field-preset" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] unsupported_spelling: "bad" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for unknown preset field") } if !strings.Contains(err.Error(), "unsupported_spelling") && !strings.Contains(err.Error(), "unused") { t.Fatalf("expected error mentioning unused/unknown field, got %v", err) } }) t.Run("empty preset id rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for empty preset id") } if !strings.Contains(err.Error(), "id must not be empty") { t.Fatalf("expected error mentioning id must not be empty, got %v", err) } }) t.Run("duplicate preset id rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "dup" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] - id: "dup" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate preset id") } if !strings.Contains(err.Error(), "duplicate preset id") { t.Fatalf("expected error mentioning duplicate preset id, got %v", err) } }) t.Run("dangling selector model rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "dangling-selector" selector: model: "non-existent-model" allowed_modes: - "direct" routes: direct: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for dangling selector model") } if !strings.Contains(err.Error(), "not found in models catalog") { t.Fatalf("expected error mentioning not found in models catalog, got %v", err) } }) t.Run("empty allowed_modes rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "no-modes" selector: model: "model-a" allowed_modes: [] routes: {} nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for empty allowed_modes") } if !strings.Contains(err.Error(), "allowed_modes must not be empty") { t.Fatalf("expected error mentioning allowed_modes must not be empty, got %v", err) } }) t.Run("unsupported mode heavy rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "heavy-path" selector: model: "model-a" allowed_modes: - "heavy" routes: heavy: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for unsupported mode 'heavy'") } if !strings.Contains(err.Error(), "not a registered mode descriptor") { t.Fatalf("expected error mentioning not a registered mode descriptor, got %v", err) } }) t.Run("missing route key for allowed mode rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "missing-route" selector: model: "model-a" allowed_modes: - "direct" - "light" routes: direct: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing route key for light mode") } if !strings.Contains(err.Error(), "missing route for allowed mode") { t.Fatalf("expected error mentioning missing route for allowed mode, got %v", err) } }) t.Run("extra route key not in allowed_modes rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "extra-route" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] light: stages: - role: "local" model: "model-a" - role: "review" model: "model-a" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for extra route key") } if !strings.Contains(err.Error(), "is not in allowed_modes") { t.Fatalf("expected error mentioning is not in allowed_modes, got %v", err) } }) t.Run("duplicate route key after normalization rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "dup-route-key" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] " direct ": stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate normalized route key") } if !strings.Contains(err.Error(), "duplicate route key") { t.Fatalf("expected error mentioning duplicate route key, got %v", err) } }) t.Run("direct mode with downstream stages rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "direct-with-stages" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: - role: "local" model: "model-a" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for direct mode with downstream stages") } if !strings.Contains(err.Error(), "declares no downstream stages") { t.Fatalf("expected error mentioning declares no downstream stages, got %v", err) } }) t.Run("required stage option overflow rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "option-overflow" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" options: opt1: "v1" opt2: "v2" opt3: "v3" opt4: "v4" opt5: "v5" - role: "review" model: "model-b" workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "tee" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "rm" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for stage option overflow on required stage") } if !strings.Contains(err.Error(), "allows at most 4 options") { t.Fatalf("expected error mentioning allows at most 4 options, got %v", err) } }) t.Run("dangling stage model rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "dangling-stage-model" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "non-existent-review-model" workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "tee" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "rm" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for dangling stage model") } if !strings.Contains(err.Error(), "not found in models catalog") { t.Fatalf("expected error mentioning not found in models catalog, got %v", err) } }) t.Run("missing prepare when write does not create parents rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "missing-prepare" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" workspace_tools: - name: "no-prepare-ws" operations: read: tool_name: "read_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "write_file" creates_parents: false schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "delete_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing prepare when write creates_parents=false") } if !strings.Contains(err.Error(), "prepare") && !strings.Contains(err.Error(), "does not create parents") { t.Fatalf("expected error mentioning prepare/creates_parents, got %v", err) } }) t.Run("duplicate allowed mode rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "dup-mode" selector: model: "model-a" allowed_modes: - "direct" - "direct" routes: direct: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate allowed mode") } if !strings.Contains(err.Error(), "duplicate allowed mode") { t.Fatalf("expected error mentioning duplicate allowed mode, got %v", err) } }) t.Run("duplicate workspace alternative name rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "dup-alt" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" workspace_tools: - name: "ws-dup" operations: read: tool_name: "cat" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "tee" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "rm" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" - name: "ws-dup" operations: read: tool_name: "cat" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "tee" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "rm" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate workspace alternative name") } if !strings.Contains(err.Error(), "duplicate workspace_tools alternative name") { t.Fatalf("expected error mentioning duplicate workspace_tools alternative name, got %v", err) } }) t.Run("light wrong stage order rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "wrong-order" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "review" model: "model-b" - role: "local" model: "model-a" workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "tee" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "rm" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for light wrong stage order") } if !strings.Contains(err.Error(), "stage[0] role is") || !strings.Contains(err.Error(), "want") { t.Fatalf("expected error mentioning stage role mismatch, got %v", err) } }) t.Run("light wrong stage count rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "wrong-count" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "tee" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "rm" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for light wrong stage count") } if !strings.Contains(err.Error(), "requires stages") || !strings.Contains(err.Error(), "got 1 stages") { t.Fatalf("expected error mentioning required stages count, got %v", err) } }) t.Run("light missing read operation rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "missing-read" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" workspace_tools: - name: "no-read-ws" operations: write: tool_name: "write_file" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "delete_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing read operation") } if !strings.Contains(err.Error(), "requires operation \"read\"") { t.Fatalf("expected error mentioning missing read operation, got %v", err) } }) t.Run("light missing write operation rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "missing-write" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" workspace_tools: - name: "no-write-ws" operations: read: tool_name: "read_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" delete: tool_name: "delete_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing write operation") } if !strings.Contains(err.Error(), "requires operation \"write\"") { t.Fatalf("expected error mentioning missing write operation, got %v", err) } }) t.Run("light missing delete operation rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "missing-delete" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" workspace_tools: - name: "no-delete-ws" operations: read: tool_name: "read_file" schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" write: tool_name: "write_file" creates_parents: true schema_matcher: type: "object" argument_map: path: "path" result_matcher: status: "ok" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing delete operation") } if !strings.Contains(err.Error(), "requires operation \"delete\"") { t.Fatalf("expected error mentioning missing delete operation, got %v", err) } }) t.Run("custom unregistered mode rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "custom-mode" selector: model: "model-a" allowed_modes: - "fast" routes: fast: stages: [] nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for custom unregistered mode") } if !strings.Contains(err.Error(), "not a registered mode descriptor") { t.Fatalf("expected error mentioning not a registered mode descriptor, got %v", err) } }) t.Run("empty model catalog with selector reference rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" execution_presets: - id: "empty-catalog-selector" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for selector model reference when models catalog is empty") } if !strings.Contains(err.Error(), "not found in models catalog") { t.Fatalf("expected error mentioning not found in models catalog, got %v", err) } }) t.Run("empty model catalog with stage reference rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "empty-catalog-stage" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: { type: "object" } argument_map: { path: "path" } result_matcher: { status: "ok" } write: tool_name: "tee" creates_parents: true schema_matcher: { type: "object" } argument_map: { path: "path" } result_matcher: { status: "ok" } delete: tool_name: "rm" schema_matcher: { type: "object" } argument_map: { path: "path" } result_matcher: { status: "ok" } nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for stage model reference not in catalog") } if !strings.Contains(err.Error(), "not found in models catalog") { t.Fatalf("expected error mentioning not found in models catalog, got %v", err) } }) t.Run("light mode with zero workspace_tools alternatives rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" - id: "model-b" providers: prov-a: "model-b" execution_presets: - id: "no-workspace-tools" selector: model: "model-a" allowed_modes: - "light" routes: light: stages: - role: "local" model: "model-a" - role: "review" model: "model-b" nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a", "model-b"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for light mode with no workspace_tools alternatives") } if !strings.Contains(err.Error(), "requires at least one workspace_tools alternative") { t.Fatalf("expected error mentioning requires at least one workspace_tools alternative, got %v", err) } }) t.Run("workspace operation missing schema_matcher rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "missing-schema-matcher" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] workspace_tools: - name: "ws1" operations: read: tool_name: "cat" argument_map: { path: "path" } result_matcher: { status: "ok" } nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing schema_matcher") } if !strings.Contains(err.Error(), "schema_matcher must not be empty") { t.Fatalf("expected error mentioning schema_matcher must not be empty, got %v", err) } }) t.Run("workspace operation missing argument_map rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "missing-argument-map" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: { type: "object" } result_matcher: { status: "ok" } nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing argument_map") } if !strings.Contains(err.Error(), "argument_map must not be empty") { t.Fatalf("expected error mentioning argument_map must not be empty, got %v", err) } }) t.Run("workspace operation missing result_matcher rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "missing-result-matcher" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: { type: "object" } argument_map: { path: "path" } nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for missing result_matcher") } if !strings.Contains(err.Error(), "result_matcher must not be empty") { t.Fatalf("expected error mentioning result_matcher must not be empty, got %v", err) } }) t.Run("workspace operation duplicate key after normalization rejected", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "model-a" providers: prov-a: "model-a" execution_presets: - id: "dup-op-key" selector: model: "model-a" allowed_modes: - "direct" routes: direct: stages: [] workspace_tools: - name: "ws1" operations: read: tool_name: "cat" schema_matcher: { type: "object" } argument_map: { path: "path" } result_matcher: { status: "ok" } " read ": tool_name: "cat2" schema_matcher: { type: "object" } argument_map: { path: "path" } result_matcher: { status: "ok" } nodes: - id: "node-01" providers: - id: "prov-a" type: "ollama" category: "local_inference" models: ["model-a"] capacity: 2 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate operation key after normalization") } if !strings.Contains(err.Error(), "duplicate operation \"read\"") { t.Fatalf("expected error mentioning duplicate operation read, got %v", err) } }) }