From 1002f0c1775490fcf7cd2b0697d6619074efb845 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Thu, 26 Feb 2026 14:06:08 -0500 Subject: [PATCH] fix: validate decision nodes have at least 2 children in frontend and AI builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The frontend validate button was not checking that decision nodes with children have at least 2 branches, so it would pass validation but the backend publish check would reject with a 422. The AI tree validator also only checked options count, not children count — so AI-generated trees with 2 options pointing to the same single child would pass generation validation but fail at publish time. Co-Authored-By: Claude Opus 4.6 --- backend/app/core/ai_tree_validator.py | 8 ++++++-- frontend/src/store/treeEditorStore.ts | 12 +++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/backend/app/core/ai_tree_validator.py b/backend/app/core/ai_tree_validator.py index 37941066..e57767b4 100644 --- a/backend/app/core/ai_tree_validator.py +++ b/backend/app/core/ai_tree_validator.py @@ -83,12 +83,16 @@ def validate_generated_tree(tree: dict[str, Any]) -> list[str]: # Type-specific validation if node_type == "decision": options = node.get("options", []) + children = node.get("children", []) if not isinstance(options, list) or len(options) < 2: errors.append( f"Decision node '{node_id}' must have at least 2 options" ) - else: - children = node.get("children", []) + if isinstance(children, list) and len(children) > 0 and len(children) < 2: + errors.append( + f"Decision node '{node_id}' must have at least 2 children (branches)" + ) + if isinstance(options, list) and len(options) >= 2: child_ids = {c.get("id") for c in children if isinstance(c, dict)} option_ids: set[str] = set() diff --git a/frontend/src/store/treeEditorStore.ts b/frontend/src/store/treeEditorStore.ts index 6e810fb4..ce80c783 100644 --- a/frontend/src/store/treeEditorStore.ts +++ b/frontend/src/store/treeEditorStore.ts @@ -710,7 +710,17 @@ export const useTreeEditorStore = create()( message: `Decision node "${node.id}" requires at least one option`, severity: 'error' }) - } else { + } + // Decision nodes with children must have at least 2 branches + if (node.children && node.children.length > 0 && node.children.length < 2) { + errors.push({ + nodeId: node.id, + field: 'children', + message: `Decision node "${node.id}" must have at least 2 branches`, + severity: 'error' + }) + } + if (node.options && node.options.length > 0) { // Validate options node.options.forEach((opt, i) => { if (!opt.label?.trim()) {