anchor.diff:        PoolDetails, <<"default pool details">>,
         [{<<"hostname">>, fun extract_string/2},
          {<<"ports">>, fun extract_object/2},
  -       {<<"version">>, fun extract_version/2}],
  +       {<<"version">>, {optional, fun extract_version/2}}],
         fun (PoolNodeProps) ->
                 with_buckets(
                   PoolDetails, JsonGet,
  
positive.code:     expect_nested_array(
        <<"nodes">>, Object, Context,
        fun (NodeList) ->
                Nodes =
                    lists:flatmap(
                      fun (Node) ->
                              extract_node_props(Props, Context, Node)
                      end, NodeList),
                case Nodes of
                    [] ->
                        Msg = io_lib:format("(~s) unable to extract any nodes",
                                            [Context]),
                        {error, {bad_value, <<"nodes">>}, iolist_to_binary(Msg)};
                    _ ->
                        K(Nodes)
                end
        end).
  
  extract_node_props(PropsExtractor, Context, NodeStruct) when is_function(PropsExtractor) ->
      PropsExtractor(NodeStruct, Context);
  extract_node_props(Props, Context, {struct, Node}) ->
      R =
          lists:foldl(
            fun ({Prop, Extract}, Acc) ->
                    case proplists:get_value(Prop, Node) of
                        undefined ->
                            ?log_warning("Missing `~s` field in node info:~n~p",
                                         [Prop, Node]),
                            Acc;
                        Value ->
                            case Extract(Value, Context) of
                                {ok, FinalValue} ->
                                    [{Prop, FinalValue} | Acc];
                                {bad_value, Msg} ->
                                    ?log_warning("~s:~n~p", [Msg, Value]),
                                    Acc
                            end
                    end
            end, [], Props),
      [R];
  extract_node_props(_Props, Context, Node) ->
      ?log_warning("(~s) got invalid node info value:~n~p", [Context, Node]),
      [].
  
  props_to_remote_node(Props) ->
      Hostname = proplists:get_value(<<"hostname">>, Props),
  
negative.code:                     end,
      Ports = proplists:get_value(<<"ports">>, Props),
  
      %% this is ensured by `maybe_extract_important_buckets_props' function
      true = (Hostname =/= undefined),
      true = (Ports =/= undefined),
  
      case CouchApiBase0 of
          undefined ->
              ?log_debug("Skipping node without either couchApiBase or couchApiBaseHTTPS (~s)", [Hostname]),
              do_with_mcd_to_couch_uri_dict(Rest, Dict, Creds, Cert, K);
          _ ->
              {Host, _Port} = host_and_port(Hostname),
              CouchApiBase = add_credentials(CouchApiBase0, Creds),
  
              expect_nested_number(
                <<"direct">>, Ports, <<"node ports object">>,
                fun (DirectPort) ->
                        McdUri = iolist_to_binary([Host, $:, integer_to_list(DirectPort)]),
                        NewDict = dict:store(McdUri, CouchApiBase, Dict),
  
                        do_with_mcd_to_couch_uri_dict(Rest, NewDict, Creds, Cert, K)
                end)
      end.
  
  add_credentials(URLBinary, {Username, Password}) ->
      URL = binary_to_list(URLBinary),
  