"""Strict browser decision request contract; values and UI mechanics stay in Node.""" def validate_request(payload): if not isinstance(payload,dict) or set(payload)!={'states'}: raise ValueError('Expected {"states": [...]}') states=payload['states'] if not isinstance(states,list) or not 1<=len(states)<=32: raise ValueError('Expected 1–32 states') seen=set();question_count=path_count=0 for state in states: if not isinstance(state,dict) or set(state)!={'id','state','questions'}: raise ValueError('Each state requires id, state, questions') sid=state['id'] if not isinstance(sid,str) or not sid.strip() or sid in seen: raise ValueError('State IDs must be unique nonempty strings') seen.add(sid) if not isinstance(state['state'],(str,dict,list)) or not state['state']: raise ValueError('State must be nonempty text, object or list') questions=state['questions'] if not isinstance(questions,dict) or not questions: raise ValueError('Questions must be a nonempty object') for qid,q in questions.items(): if not isinstance(qid,str) or not qid.strip() or not isinstance(q,dict): raise ValueError('Invalid question') if set(q)!={'type','instructions','criteria'} or q['type']!='choice': raise ValueError('Browser API supports choice questions only') if not isinstance(q['instructions'],str) or not q['instructions'].strip(): raise ValueError('Instructions must be nonempty text') criteria=q['criteria'] if not isinstance(criteria,dict) or not 2<=len(criteria)<=255: raise ValueError('Expected 2–255 candidate actions') if any(not isinstance(k,str) or not k.strip() or not isinstance(v,str) or not v.strip() for k,v in criteria.items()): raise ValueError('Candidate IDs and descriptions must be nonempty text') question_count+=1;path_count+=len(criteria) if question_count>96 or path_count>256: raise ValueError('Request exceeds 96 questions or 256 candidate paths') return states