// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";

package cobalt;

option java_multiple_files = true;
option java_package = "com.google.cobalt";

////////////////////////////////////////////////////////////////////////////////
// NOTE: This file is used by the Cobalt client and the Cobalt servers.
// The source-of-truth of this file is located in Cobalt's open source code
// repository, and the file is copied to Android where it is used by the Cobalt
// client. Do not edit the copy of this file in this Android repo as those edits
// will be overwritten when the file is next copied.
////////////////////////////////////////////////////////////////////////////////

// An Observation is a piece of data sent from a Cobalt client to the Cobalt
// server as input to a Report.
//
// Observations are associated with a specific Metric. They are built on a
// Fuchsia client based on the Events logged for that Metric. Observations are
// associated with a specific Report. They are built for the purpose of
// generating that Report. They are transmitted from the Fuchsia client to
// the Cobalt server where they are aggregated and analyzed in order to generate
// the Report.
//
// Observations may store their data using special privacy-preserving encodings.
// The specification of how to do this is part of the definition of a Report.
// Observations are built for a particular Report and so use an encoding
// appropriate for that Report.
//
// There are different types of Observations that are appropriate for different
// types of Metrics and different types of Reports.
//
// An Observation is always transmitted and stored along with
// some ObservationMetadata that describes, among other things, which Metric
// and which Report it is for and on which day the Observation was formed.
//
// Observations are transmitted from the client to the server encrypted, inside
// the |ciphertext| field of an EncryptedMessage. Many encrypted Observations
// are transmitted together inside of an ObservationBatch.
message Observation {
  // Next observation_type ID: 9
  // Next general ID: 1002;
  reserved 1, 2, 3, 4, 5, 6, 7, 8, 1000;

  // An Observation has one of the following types.
  oneof observation_type {
    SumAndCountObservation sum_and_count = 9;
    IntegerObservation integer = 10;
    IndexHistogramObservation index_histogram = 11;
    StringHistogramObservation string_histogram = 12;
    PrivateIndexObservation private_index = 13;
    ReportParticipationObservation report_participation = 10000;
  }

  // A quasi-unique identifier for this observation. This is randomly generated
  // on the client and used on the server as part of a fully-unique identifier.
  // This field allows the operation of sending an Observation to the Cobalt
  // server to be idempotent: If the same Observation is transmitted twice then
  // the server will store the observation only once.
  bytes random_id = 1001;
}

// Observations of type SumAndCountObservation contain one or more triples of
// event vectors, a signed integer recording a sum and an unsigned integer
// recording a count.
//
// This type of observation is used only for the FLEETWIDE_MEANS report type.
message SumAndCountObservation {
  message SumAndCount {
    // Event vector to which the sum and count are associated.
    repeated uint32 event_codes = 1;

    // The device-level sum.
    sint64 sum = 2;

    // the device-level count.
    uint64 count = 3;
  }

  repeated SumAndCount sums_and_counts = 1;
}

// Observations of type IntegerObservation contain one or more pairs of
// event vectors and signed integers.
//
// This type of observation is used for the following report types:
// FLEETWIDE_OCCURRENCE_COUNTS
// HOURLY_VALUE_NUMERIC_STATS
// HOURLY_VALUE_HISTOGRAMS
// UNIQUE_DEVICE_COUNTS
// UNIQUE_DEVICE_NUMERIC_STATS
// UNIQUE_DEVICE_HISTOGRAMS
message IntegerObservation {
  message Value {
    // Event vector to which the value is associated.
    repeated uint32 event_codes = 1;

    // The value depends upon the report type.
    //
    // FLEETWIDE_OCCURRENCE_COUNTS
    // Device-level count of events with the associated event vector.
    // Value is between 0 and the configured maximum count (inclusive).
    //
    // UNIQUE_DEVICE_COUNTS
    // 1 if the associated event vector was observed.
    //
    // HOURLY_VALUE_NUMERIC_STATS
    // UNIQUE_DEVICE_NUMERIC_STATS
    // HOURLY_VALUE_HISTOGRAMS
    // UNIQUE_DEVICE_HISTOGRAMS
    // Device-level aggregate value for the associated event vector.
    sint64 value = 2;
  }

  repeated Value values = 1;
}

// IndexHistogram represents a list of counts for each bucket of a histogram
// associated with a particular event vector.
message IndexHistogram {
  // Event vector to which the histogram is associated.
  repeated uint32 event_codes = 1;

  // bucket_counts[i] is the count for the bucket_indices[i]th index in the
  // histogram.
  repeated uint32 bucket_indices = 2;
  repeated sint64 bucket_counts = 3;
}

// Observations of type IndexHistogramObservation contain one or more pairs of
// event vectors and lists of bucket counts.
//
// This type of observation is used with the FLEETWIDE_HISTOGRAMS report type.
message IndexHistogramObservation {
  repeated IndexHistogram index_histograms = 1;
}

// Observations of the type StringHistogramObservation contain a list of strings
// mapping string hashes to indices and one or more pairs of event vectors
// and lists of bucket counts.
//
// This type of observation is used for the following report types:
// STRING_COUNTS
// UNIQUE_DEVICE_STRING_COUNTS
message StringHistogramObservation {
  // TODO(b/322409910): Delete string_hashes after clients stop sending
  // the field.
  repeated bytes string_hashes = 1 [deprecated = true];

  // List of hashes of strings (hashed using Farmhash Fingerprint64).
  // The string that hashes to the bytes value in the ith position in
  // |string_hashes| corresponds to the bucket with index i in each of the
  // |bucket_indices| values in |string_histograms|.
  //
  // Only one of `string_hashes` or `string_hashes_ff64` should be used.
  repeated bytes string_hashes_ff64 = 3;

  repeated IndexHistogram string_histograms = 2;
}

// An observation of type PrivateIndexObservation contains a single integer.
// Observations of this type are produced by the PrivacyEncoder: given a single
// Observation of some other type, the PrivacyEncoder outputs one or more
// PrivateIndexObservations. All data for reports with a nontrivial
// privacy mechanism will be transported from client to server in the form of
// PrivateIndexObservations.
//
// The field |index| of a PrivateIndexObservation is an index into an
// enumeration of the set of possible Observations of another type (after
// bucketing some parameters, as specified in the ReportDefinition for which the
// Observation was generated.) The details of this enumeration depend on the
// type of Observation which was given to the PrivacyEncoder.
message PrivateIndexObservation {
  uint64 index = 1;
}

// A pair consisting of a bucket index and a count. Each bucket is
// an integer range. The definition of the buckets and their indices
// is given in the MetricDefinition.
// TODO(b/262785064): don't use this for the public LoggerInterface.
message HistogramBucket {
  // The index of one of the buckets.
  uint32 index = 1;
  // The count for that bucket.
  uint64 count = 2;
}

// Observations of this type are used to signal that a given device was
// collecting data for a given report, over some window of time. This
// Observation type has no required fields.
//
// ReportParticipationObservations are produced by the PrivacyEncoder and
// consumed by the ReportGenerator for reports that use local differential
// privacy.
message ReportParticipationObservation {}