syntax = "proto3";

package nexuscrm.runtime.v1;

import "common/v1/common.proto";

option go_package = "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1;runtimev1";

// OutboundIntentService exposes Runtime-owned immutable intents to one
// authorized Integration consumer. It deliberately exposes no provider-effect
// claim, credential, retry, or provider-dispatch RPC. CommitOutboundResult is
// the narrow, idempotent hand-back for Runtime's metadata-authorized local
// projection after Integration has durably recorded provider success.
service OutboundIntentService {
  rpc ReadOutboundIntentGeneration(ReadOutboundIntentGenerationRequest) returns (ReadOutboundIntentGenerationResponse);
  rpc ListPendingOutboundIntents(ListPendingOutboundIntentsRequest) returns (ListPendingOutboundIntentsResponse);
  rpc AcknowledgeOutboundIntent(AcknowledgeOutboundIntentRequest) returns (AcknowledgeOutboundIntentResponse);
  rpc CommitOutboundResult(CommitOutboundResultRequest) returns (CommitOutboundResultResponse);
  // Opens only a frozen attachment belonging to the exact accepted intent and
  // Integration command. It is not an arbitrary Runtime Files read surface.
  rpc OpenOutboundMailAttachment(OpenOutboundMailAttachmentRequest) returns (stream OpenOutboundMailAttachmentResponse);
}

// OutboundIntentNoEffectService is the additive terminal hand-back for an
// accepted command that cannot be dispatched because its Catalog authority is
// retired. It is deliberately separate from OutboundIntentService so the
// published v1 Go client and server interfaces remain source-compatible.
service OutboundIntentNoEffectService {
  rpc CommitOutboundNoEffect(CommitOutboundNoEffectRequest) returns (CommitOutboundNoEffectResponse);
}

// The generation is a durable scheduling cursor only. It contains no intent
// payload and grants no claim or delivery authority.
message ReadOutboundIntentGenerationRequest {
  uint64 after_generation = 1;
}

message ReadOutboundIntentGenerationResponse {
  uint64 generation = 1;
  nexuscrm.common.v1.ConsistencyReceipts receipts = 2;
}

message ListPendingOutboundIntentsRequest {
  uint32 limit = 1;
  optional uint64 min_catalog_revision = 2;
  // Zero is the legacy v1 operation set (UPSERT/DELETE). SEND_MAIL may be
  // returned only when the consumer explicitly advertises version 2.
  uint32 max_operation_set_version = 3;
}

message OutboundIntentBindingReference {
  string kind = 1;
  string owner_pack = 2;
  string pack_installation_id = 3;
  string pack_payload_digest = 4;
  string business_key = 5;
  uint64 definition_version = 6;
}

enum OutboundIntentOperation {
  OUTBOUND_INTENT_OPERATION_UNSPECIFIED = 0;
  OUTBOUND_INTENT_OPERATION_UPSERT = 1;
  OUTBOUND_INTENT_OPERATION_DELETE = 2;
  OUTBOUND_INTENT_OPERATION_SEND_MAIL = 3;
}

message OutboundIntent {
  reserved 16, 17;
  reserved "effect_root_id", "effect_generation_id";

  string intent_id = 1;
  string idempotency_key = 2;
  uint32 payload_format_version = 3;
  string payload_digest = 4;
  uint64 catalog_revision = 5;
  OutboundIntentOperation operation = 6;
  string source_object = 7;
  string source_record_id = 8;
  string connector_owner_key = 9;
  string action_slot_id = 10;
  string destination_slot_id = 11;
  repeated OutboundIntentBindingReference bindings = 12;
  bytes canonical_payload = 13;
  string flow_developer_name = 14;
  string flow_action_name = 15;
  // The coordinates are an optional pair. Existing producers may omit both
  // and retain their identifier and idempotency-key authority. When present,
  // both are required; together with trusted delegation scope and
  // action_slot_id, they identify one logical effect. Generation remains stable
  // across retries and changes for repeated occurrences of the slot.
  string logical_effect_root_id = 18;
  string logical_effect_generation_id = 19;
}

message ListPendingOutboundIntentsResponse {
  repeated OutboundIntent intents = 1;
  nexuscrm.common.v1.ConsistencyReceipts receipts = 2;
}

enum OutboundIntentAdmissionOutcome {
  OUTBOUND_INTENT_ADMISSION_OUTCOME_UNSPECIFIED = 0;
  OUTBOUND_INTENT_ADMISSION_OUTCOME_ACCEPTED = 1;
  OUTBOUND_INTENT_ADMISSION_OUTCOME_REJECTED = 2;
}

message AcknowledgeOutboundIntentRequest {
  string intent_id = 1;
  string payload_digest = 2;
  uint64 catalog_revision = 3;
  OutboundIntentAdmissionOutcome outcome = 4;
  string integration_command_id = 5;
  string rejection_code = 6;
}

message AcknowledgeOutboundIntentResponse {
  string intent_id = 1;
  OutboundIntentAdmissionOutcome outcome = 2;
  bool duplicate = 3;
  nexuscrm.common.v1.ConsistencyReceipts receipts = 4;
}

message CommitOutboundResultRequest {
  string intent_id = 1;
  string payload_digest = 2;
  uint64 catalog_revision = 3;
  string integration_command_id = 4;
  string remote_id = 5;
  // Typed results are additive and mutually exclusive with remote_id. They
  // carry closed provider-neutral outcomes, never raw provider responses.
  uint32 result_format_version = 6;
  string result_digest = 7;
  bytes canonical_result = 8;
}

message CommitOutboundResultResponse {
  string intent_id = 1;
  bool duplicate = 2;
  nexuscrm.common.v1.ConsistencyReceipts receipts = 3;
}

message CommitOutboundNoEffectRequest {
  string intent_id = 1;
  string payload_digest = 2;
  uint64 catalog_revision = 3;
  string integration_command_id = 4;
  // The semantic contract admits only its closed provider-neutral reason set.
  string reason = 5;
}

message CommitOutboundNoEffectResponse {
  string intent_id = 1;
  string reason = 2;
  bool duplicate = 3;
  // Receipts identify the strictly newer trusted serving Catalog authority.
  nexuscrm.common.v1.ConsistencyReceipts receipts = 4;
}

message OpenOutboundMailAttachmentRequest {
  string intent_id = 1;
  string payload_digest = 2;
  uint64 catalog_revision = 3;
  string integration_command_id = 4;
  uint32 attachment_index = 5;
}

message OpenOutboundMailAttachmentResponse {
  string file_name = 1;
  string content_type = 2;
  uint64 content_length = 3;
  string content_digest = 4;
  bytes data = 5;
  nexuscrm.common.v1.ConsistencyReceipts receipts = 6;
}
