anchor.diff:      atm_data_type:value_constraints()
   ) ->
       ok | no_return().
  -assert_meets_constraints(_AtmWorkflowExecutionAuth, _Value, _ValueConstraints) ->
  -    %% TODO validate fields
  -    ok.
  +assert_meets_constraints(_AtmWorkflowExecutionAuth, Value, _ValueConstraints) ->
  +    try
  +        lists:foreach(fun({Index, Measurement}) ->
  +            check_implicit_measurement_constraints(Index - 1, Measurement)
  +        end, lists_utils:enumerate(Value))
  +    catch
  +        throw:{unverified_constraints, UnverifiedConstraints} ->
  +            throw(?ERROR_ATM_DATA_VALUE_CONSTRAINT_UNVERIFIED(
  +                Value, ?DATA_TYPE, UnverifiedConstraints
  +            ));
  +        throw:Error ->
  +            throw(Error);
  +        _:_ ->
  +            throw(?ERROR_ATM_DATA_TYPE_UNVERIFIED(Value, ?DATA_TYPE))
  +    end.
   
   
   %%%===================================================================
  
positive.code: -behaviour(atm_data_validator).
  -behaviour(atm_data_compressor).
  
  %% atm_data_validator callbacks
  -export([assert_meets_constraints/3]).
  
  %% atm_data_compressor callbacks
  -export([compress/1, expand/2]).
  
  
  %%%===================================================================
  
negative.code:     {ok, atm_value:expanded()}.
  expand(_AtmWorkflowExecutionAuth, Value) ->
      {ok, Value}.
  
  
  %%%===================================================================
  %%% Internal functions
  %%%===================================================================
  
  
  %% @private
  -spec check_implicit_measurement_constraints(non_neg_integer(), atm_value:expanded()) ->
      ok | no_return().
  check_implicit_measurement_constraints(Index, #{
      <<"tsName">> := TsName,
      <<"timestamp">> := Timestamp,
      <<"value">> := MeasurementValue
  }) ->
      is_binary(TsName) orelse throw({unverified_constraints, #{
          ?FIELD_PATH(Index, <<"tsName">>) => <<"String">>
      }}),
  
      (is_integer(Timestamp) andalso Timestamp > 0) orelse throw({unverified_constraints, #{
          ?FIELD_PATH(Index, <<"timestamp">>) => <<"Non negative integer">>
      }}),
  
      is_number(MeasurementValue) orelse throw({unverified_constraints, #{
          ?FIELD_PATH(Index, <<"value">>) => <<"Number">>
      }}),
  
      ok.
  