feat: add backend validation for fallback steps (Task 16)
Validate fallback_steps in procedural flow validation: required fields, no nested fallback_steps, no duplicate IDs. Add FallbackStepRecord schema and fallback_decisions field to SessionResponse. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -208,6 +208,34 @@ def validate_procedural_structure(tree_structure: dict[str, Any]) -> tuple[bool,
|
||||
if content_type and content_type not in VALID_CONTENT_TYPES:
|
||||
errors.append({"field": f"{path}.content_type", "message": f"Invalid content_type: {content_type}. Must be one of: {', '.join(VALID_CONTENT_TYPES)}"})
|
||||
|
||||
# Validate fallback_steps if present (one level deep only)
|
||||
fallback_steps = step.get("fallback_steps")
|
||||
if fallback_steps is not None:
|
||||
if not isinstance(fallback_steps, list):
|
||||
errors.append({"field": f"{path}.fallback_steps", "message": "fallback_steps must be an array"})
|
||||
else:
|
||||
fallback_ids: set[str] = set()
|
||||
for j, fb_step in enumerate(fallback_steps):
|
||||
fb_path = f"{path}.fallback_steps[{j}]"
|
||||
if not isinstance(fb_step, dict):
|
||||
errors.append({"field": fb_path, "message": "Fallback step must be an object"})
|
||||
continue
|
||||
fb_id = fb_step.get("id")
|
||||
if not fb_id:
|
||||
errors.append({"field": f"{fb_path}.id", "message": "Fallback step must have an id"})
|
||||
elif fb_id in seen_ids or fb_id in fallback_ids:
|
||||
errors.append({"field": f"{fb_path}.id", "message": f"Duplicate fallback step id: {fb_id}"})
|
||||
else:
|
||||
fallback_ids.add(fb_id)
|
||||
seen_ids.add(fb_id)
|
||||
if not fb_step.get("title"):
|
||||
errors.append({"field": f"{fb_path}.title", "message": "Fallback step must have a non-empty title"})
|
||||
fb_type = fb_step.get("type")
|
||||
if fb_type and fb_type not in VALID_STEP_TYPES:
|
||||
errors.append({"field": f"{fb_path}.type", "message": f"Invalid fallback step type: {fb_type}"})
|
||||
if fb_step.get("fallback_steps"):
|
||||
errors.append({"field": f"{fb_path}.fallback_steps", "message": "Fallback steps cannot have their own fallback_steps (one level deep only)"})
|
||||
|
||||
# Must have exactly one end step
|
||||
if end_count == 0:
|
||||
errors.append({"field": "tree_structure.steps", "message": "Procedural tree must have a procedure_end step as the last step"})
|
||||
|
||||
Reference in New Issue
Block a user