syntax = "proto3";

package nominal.ingest_transform.v1;

import "nominal/protos/ingest/v2/common.proto";
import "nominal/protos/ingest/v2/file_ingest.proto";

option java_multiple_files = true;
option java_package = "io.nominal.ingest_transform.v1";

// Wire types for ingest transform Temporal workflows and activities. Each
// operation uses a request/response message so the payloads can evolve without
// changing Temporal method signatures.

message ExecuteIngestTransformRequest {
  string transform_uuid = 1;
}

message ExecuteIngestTransformResponse {}

message LoadRunnableTransformRequest {
  string transform_uuid = 1;
}

message LoadRunnableTransformResponse {
  reserved 5, 8;
  reserved "source_payload_json", "timestamp_metadata_json";

  string transform_uuid = 1;
  string ingest_job_uuid = 2;
  string org_uuid = 3;
  IngestTransformType transform_type = 4;
  map<string, string> arguments = 6;
  optional string extractor_rid = 7;
  // Full ingest job RID, for log correlation with the rest of the ingest pipeline.
  string ingest_job_rid = 13;
  // Timestamp metadata submitted with the transform, if any. Falls back to the
  // extractor's own metadata when absent.
  optional nominal.ingest.v2.TimestampMetadata timestamp_metadata = 9;
  // Typed payload, discriminated by transform_type.
  oneof payload {
    ContainerizedTransformPayload containerized = 10;
    McapTransformPayload mcap = 11;
    DataflashTransformPayload dataflash = 12;
    ParquetArchiveTransformPayload parquet_archive = 14;
    FileCopyTransformPayload file_copy = 15;
  }
}

// Payload for an MCAP transform: worker-mcap converts the source file into an avro stream
// that is then queued as a dataset file. Also the schema of the
// `ingest_transforms.source_payload` jsonb column for MCAP rows (protobuf JSON).
message McapTransformPayload {
  nominal.ingest.v2.IngestSource source = 1;
  map<string, string> tags = 2;
  // Which mcap channels to ingest. All channels when unset.
  McapChannelFilter channels = 3;
  bool ignore_invalid_topics = 4;
}

// Selects mcap channels by topic name. All channels are ingested when neither list is set.
message McapChannelFilter {
  oneof filter {
    McapTopics include_topics = 1;
    McapTopics exclude_topics = 2;
  }
}

message McapTopics {
  repeated string topics = 1;
}

// Payload for a DATAFLASH transform: worker-mcap converts the dataflash log into an avro
// stream that is then queued as a dataset file. Also the schema of the
// `ingest_transforms.source_payload` jsonb column for DATAFLASH rows (protobuf JSON).
message DataflashTransformPayload {
  nominal.ingest.v2.IngestSource source = 1;
  map<string, string> tags = 2;
}

// Payload for a PARQUET_ARCHIVE transform: the source is an archive (.tar/.tar.gz/.zip) of
// parquet files. The transform extracts each member and ingests it as an independent parquet
// dataset file, so the member-level parquet config is carried here. Also the schema of the
// `ingest_transforms.source_payload` jsonb column for PARQUET_ARCHIVE rows (protobuf JSON).
message ParquetArchiveTransformPayload {
  nominal.ingest.v2.IngestSource source = 1;
  nominal.ingest.v2.TimestampMetadata timestamp_metadata = 2;
  nominal.ingest.v2.ParquetFormat format = 3;
  map<string, string> units = 4;
  map<string, string> tags = 5;
  optional string channel_prefix = 6;
  // Per-column channel-name overrides applied to every extracted member, mirroring
  // FileIngestOptions.channel_name_overrides on the originating request.
  map<string, string> channel_name_overrides = 7;
}

// Payload for a FILE_COPY transform: a direct file whose source lives outside the uploads bucket
// (external S3, GCS, or a presigned URL). The transform copies the source into the uploads bucket
// off the request thread and then queues it as a normal dataset file using the original ingest
// options. Also the schema of the `ingest_transforms.source_payload` jsonb column for file-copy rows.
message FileCopyTransformPayload {
  nominal.ingest.v2.FileIngestItem file = 1;
  map<string, string> tags = 2;
}

// Payload for a CONTAINERIZED transform. Also the schema of the
// `ingest_transforms.source_payload` jsonb column for containerized rows, which stores the
// protobuf-JSON rendering of this message.
message ContainerizedTransformPayload {
  // Extractor input sources keyed by the container environment variable they bind to.
  map<string, nominal.ingest.v2.IngestSource> sources = 1;
  map<string, string> tags = 2;
  repeated string runs_to_expand = 3;
}

message MarkTransformSucceededRequest {
  string transform_uuid = 1;
}

// Whether a transform failure was caused by the user's input (e.g. an invalid MCAP) or by an
// internal/system fault. Drives per-type failure-rate alerting: only SYSTEM failures should page.
enum TransformFailureKind {
  TRANSFORM_FAILURE_KIND_UNSPECIFIED = 0;
  TRANSFORM_FAILURE_KIND_USER = 1;
  TRANSFORM_FAILURE_KIND_SYSTEM = 2;
}

message MarkTransformFailedRequest {
  string transform_uuid = 1;
  string safe_error_message = 2;
  TransformFailureKind failure_kind = 3;
}

enum IngestTransformType {
  INGEST_TRANSFORM_TYPE_UNSPECIFIED = 0;
  INGEST_TRANSFORM_TYPE_CONTAINERIZED = 1;
  INGEST_TRANSFORM_TYPE_MCAP = 2;
  INGEST_TRANSFORM_TYPE_DATAFLASH = 3;
  INGEST_TRANSFORM_TYPE_PARQUET_ARCHIVE = 4;
  INGEST_TRANSFORM_TYPE_FILE_COPY = 5;
}
