class FlowEngine::Node
@attr_reader max_clarifications [Integer] max follow-up rounds for :ai_intake steps (default: 0)
@attr_reader visibility_rule [Rules::Base, nil] rule controlling whether this node is visible (DAG mode)
@attr_reader transitions [Array<Transition>] ordered list of conditional next-step rules
@attr_reader fields [Array, nil] field names for number_matrix etc.; nil otherwise
@attr_reader option_labels [Hash, nil] key => display label mapping (nil when options are plain strings)
@attr_reader options [Array, nil] option keys for select steps; nil for other types
@attr_reader question [String] prompt text for the step
@attr_reader type [Symbol] input type (e.g. :multi_select, :number_matrix, :ai_intake)
@attr_reader id [Symbol] unique step identifier
Used by {Engine} to determine the next step and by UI/export to render the step.
A single step in the flow: question metadata, input config, and conditional transitions.
def ai_intake?
-
(Boolean)- true if this is an AI intake step
def ai_intake? type == :ai_intake end
def extract_options(raw)
Normalizes options: a Hash is split into keys (options) and the full hash (option_labels);
def extract_options(raw) case raw when Hash @options = raw.keys.map(&:to_s).freeze @option_labels = raw.transform_keys(&:to_s).freeze when Array @options = raw.freeze @option_labels = nil else @options = nil @option_labels = nil end end
def initialize(id:, # rubocop:disable Metrics/ParameterLists
-
max_clarifications(Integer) -- max follow-up rounds for :ai_intake (default: 0) -
visibility_rule(Rules::Base, nil) -- optional rule for visibility (default: always visible) -
transitions(Array) -- conditional next-step transitions (default: []) -
fields(Array, nil) -- field list for matrix-style steps -
options(Array, Hash, nil) -- option list or key=>label hash for select steps -
decorations(Object, nil) -- optional UI decorations (not used by engine) -
question(String) -- label/prompt -
type(Symbol) -- step/input type -
id(Symbol) -- step id
def initialize(id:, # rubocop:disable Metrics/ParameterLists type:, question:, decorations: nil, options: nil, fields: nil, transitions: [], visibility_rule: nil, max_clarifications: 0) @id = id @type = type @question = question @decorations = decorations extract_options(options) @fields = fields&.freeze @transitions = transitions.freeze @visibility_rule = visibility_rule @max_clarifications = max_clarifications freeze end
def next_step_id(answers)
-
(Symbol, nil)- id of the next step, or nil if no transition matches (flow end)
Parameters:
-
answers(Hash) -- current answer state (step_id => value)
def next_step_id(answers) match = transitions.find { |t| t.applies?(answers) } match&.target end
def visible?(answers)
-
(Boolean)- true if no visibility_rule, else result of rule evaluation
Parameters:
-
answers(Hash) -- current answer state
def visible?(answers) return true if visibility_rule.nil? visibility_rule.evaluate(answers) end