# File lib/ruote/worker.rb, line 440
    def launch(msg)

      tree = msg['tree']
      variables = msg['variables']
      wi = msg['workitem']

      exp_class = @context.expmap.expression_class(tree.first)

      # msg['wfid'] only:  it's a launch
      # msg['fei']:        it's a sub launch (a supplant ?)

      if is_launch?(msg, exp_class)

        name = tree[1]['name'] || tree[1].keys.find { |k| tree[1][k] == nil }
        revision = tree[1]['revision'] || tree[1]['rev']

        wi['wf_name'] ||= name
        wi['wf_revision'] ||= revision
        wi['wf_launched_at'] ||= Ruote.now_to_utc_s

        wi['sub_wf_name'] = name
        wi['sub_wf_revision'] = revision
        wi['sub_wf_launched_at'] = Ruote.now_to_utc_s
      end

      exp_hash = {

        'fei' => msg['fei'] || {
          'engine_id' => @context.engine_id,
          'wfid' => msg['wfid'],
          'subid' => Ruote.generate_subid(msg.inspect),
          'expid' => msg['expid'] || '0' },

        'parent_id' => msg['parent_id'],
        'variables' => variables,
        'applied_workitem' => wi,

        'forgotten' => msg['forgotten'],
        'lost' => msg['lost'],
        'flanking' => msg['flanking'],
        'attached' => msg['attached'],
        'supplanted' => msg['supplanted'],

        'stash' => msg['stash'],
        'trigger' => msg['trigger'],
        'on_reply' => msg['on_reply']
      }

      if not exp_class

        exp_class = Ruote::Exp::RefExpression

      elsif is_launch?(msg, exp_class)

        def_name, tree = Ruote::Exp::DefineExpression.reorganize(tree)
        variables[def_name] = [ '0', tree ] if def_name
        exp_class = Ruote::Exp::SequenceExpression
      end

      exp_hash = exp_hash.reject { |k, v| v.nil? }
        # compact nils away

      exp_hash['original_tree'] = tree
        # keep track of original tree

      exp = exp_class.new(@context, exp_hash)

      exp.initial_persist
      exp.do(:apply, msg)
    end