chromium/components/variations/proto/layer.proto

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

syntax = "proto2";

option optimize_for = LITE_RUNTIME;
option java_package = "org.chromium.components.variations";

package variations;

// A Layer divides Variations clients into disjoint LayerMembers based on client
// entropy values, allowing potentially conflicting studies to be performed on
// separate client subsets.

// Each layer consists of N slots, and each Chrome client instance will randomly
// select a specific slot to be "active" within that layer based on the layer's
// salt and the client's entropy source value. That slot will be part of a range
// within a specific LayerMember. Each study that participates in a layer points
// to a particular LayerMember within that layer. Only the studies pointing to
// the active LayerMember will be active for a given client.
// Example:
//    LayerFoo:
//        num_slots=10: |0, 1, 2, 3, 4, 5, 6, 7, 8, 9|
//        LayerMembers: <0   -   3>, <4     -       9>
//                        ^Member1^    ^Member2^.
//
//    In this example, the Member1 LayerMember has four slots and
//    Member2 has six out of ten total. This means studies pointing to
//    Member1 will receive ~40% of the population and Member2 ~60%.

// Next tag: 6
message Layer {
  message LayerMember {
    message SlotRange {
      // First slot in the range (inclusive). This range has to be
      // in the [0..`num_slots`) range of the layer.
      optional uint32 start = 1;
      // Last slot in the range (inclusive).
      optional uint32 end = 2;
    }

    // An id (unique within the Layer) that studies will use to refer to this
    // particular member.
    optional uint32 id = 1;
    // Ranges of slots that belong to this member. These slot ranges must not
    // overlap with the slot ranges of other members within the layer, so
    // that at most one member within the layer will be active. The ranges must
    // be listed in increasing order.
    repeated SlotRange slots = 2;
  }

  // ID for the layer, must be unique across all layers. Studies will specify
  // a <layer_id, layer_member_id> pair to become part of a layer.
  optional uint32 id = 1;

  // Total number of slots within the layer. There are constraints on the number
  // of slots when a low entropy source is used (100, initially) to alleviate
  // skew in the bucket populations.
  optional uint32 num_slots = 2;

  // Layer members, which occupy disjoint subsets of the [0, `num_slots`) range.
  // Not all slots have to be used, and normally won't in order to reserve space
  // within the layer. Each study that participates in a layer is associated
  // with a single layer member.
  repeated LayerMember members = 3;

  // A salt which is used as an input to a hash function together with the
  // output of the chosen entropy source, to choose an active slot within the
  // layer. If salt is unset or 0, the layer id will be used instead.
  optional uint32 salt = 4;

  enum EntropyMode {
    // Use the default entropy source when selecting slots. This will use the
    // high entropy source for the clients that have it, and falls back to the
    // low entropy source for other clients.
    DEFAULT = 0;

    // Use the low entropy source.
    LOW = 1;

    // Use the limited entropy source.
    LIMITED = 2;
  }

  // Which of the above entropy modes should be used to select a slot.
  optional EntropyMode entropy_mode = 5;
}

// A Study can optionally specify a LayerMemberReference which will constrain it
// to one or more layer members of the specified layer.
message LayerMemberReference {
  // Reference to the layer with this specific ID.
  optional uint32 layer_id = 1;

  // References to members within the above layer.
  //
  // New code should use `layer_member_ids` instead. Older clients only support
  // `layer_member_id`, and values in `layer_member_ids` are ignored. Newer
  // clients support both fields for backward compatibility. A study that uses
  // `layer_member_ids` needs to have a `min_version` that is greater than
  // the minimum version that supports `layer_member_ids`.
  // TODO(crbug.com/345611804): Amend this comment with the minimum version when
  // it is known.
  //
  // Specifying more than one `layer_member_id` can be used to adjust the active
  // percentage of a study:
  //   - Adding a `layer_member_id` will result in clients randomized to that
  //     layer member to be part of this study (and be randomized into its
  //     groups).
  //   - Removing a `layer_member_id` will take out clients randomized to that
  //     layer member from the study.
  //
  optional uint32 layer_member_id = 2;
  repeated uint32 layer_member_ids = 3 [packed = true];
}