// running-process v1 broker — wire envelope schema.
//
// FROZEN FOREVER once v1.0 ships. Any breaking change to this file
// forces a new running-process-broker-v2 binary; v1 source files are
// never edited. See issue #228 ("Frozen-forever commitments") for the
// full rationale.
//
// Wire-level commitments (NOT encoded in proto3 — enforced in code):
//   - Length framing: [u8 framing_version=1][u32 LE body_length][prost body]
//   - Max frame size: 16 MiB; broker disconnects on overflow.
//   - Max Hello size: 64 KiB; broker returns Refused on overflow.
//   - String caps: service_name <= 64, wanted_version <= 64,
//                  client_version <= 128, client_lib_* <= 64.
//   - Prost decoder keeps default 100-recursion-depth; no-recursion-limit
//     is forbidden.

syntax = "proto3";
package running_process.broker.v1;

// Every control-plane frame on a broker connection.
message Frame {
  uint32 envelope_version = 1;     // ALWAYS 1 in v1 broker. Frozen.
  FrameKind kind = 2;
  uint32 payload_protocol = 3;     // 0x00 for Hello/HelloReply; 0xAD01 for admin verbs
  bytes payload = 4;               // OPAQUE for non-control kinds
  uint64 request_id = 5;
  PayloadEncoding payload_encoding = 6;
  uint64 deadline_unix_ms = 7;
  string traceparent = 8;          // W3C trace context
  string tracestate = 9;
  reserved 10 to 15;               // reserve hot-path 1-byte-tag slots
}

enum FrameKind {
  FRAME_KIND_REQUEST = 0;
  FRAME_KIND_RESPONSE = 1;
  FRAME_KIND_EVENT = 2;            // broker -> client push
  FRAME_KIND_CANCEL = 3;
}

enum PayloadEncoding {
  PAYLOAD_ENCODING_NONE = 0;
  PAYLOAD_ENCODING_ZSTD = 1;
  PAYLOAD_ENCODING_SNAPPY = 2;
  PAYLOAD_ENCODING_LZ4 = 3;
}

// Required first message on every new connection to a broker pipe.
message Hello {
  uint32 client_min_protocol = 1;
  uint32 client_max_protocol = 2;
  string service_name = 3;          // [a-z0-9-]{1,64} (lowercase-normalized, regex-validated)
  string wanted_version = 4;        // ^[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9.]+)?$ (semver)
  string client_version = 5;        // informational
  uint64 client_capabilities = 6;   // capability bitmap (additive feature flags)
  bytes auth_token = 7;             // reserved for future capability delegation
  string request_id = 8;            // per-Hello correlation
  uint64 connection_id = 9;         // broker-assigned (zero on Hello, set on HelloReply echo)
  uint32 peer_pid = 10;             // client-self-reported; broker verifies via SO_PEERCRED
  string client_lib_name = 11;      // telemetry
  string client_lib_version = 12;
  bytes peer_attestation_nonce = 13; // reserved (challenge-response)
  bytes capability_token = 14;       // reserved (capability delegation)
  uint64 client_keepalive_secs = 15; // proposed idle keepalive
  reserved 16 to 20;
}

message HelloReply {
  oneof result {
    Negotiated negotiated = 1;
    Refused refused = 2;
  }
}

message Negotiated {
  uint32 negotiated_protocol = 1;
  string daemon_version = 2;
  string backend_pipe = 3;          // pipe name client connects to
  repeated string warnings = 4;
  uint64 server_capabilities = 5;
  uint64 keepalive_interval_secs = 6;
  bytes handle_passed_token = 7;    // present when broker used DuplicateHandle/SCM_RIGHTS handoff
  uint64 connection_id = 8;
}

message Refused {
  string reason = 1;
  uint32 daemon_min_protocol = 2;
  uint32 daemon_max_protocol = 3;
  ErrorCode code = 4;
  map<string, string> details = 5;
  uint64 retry_after_ms = 6;
}

enum ErrorCode {
  ERROR_CODE_UNSPECIFIED = 0;
  ERROR_VERSION_UNSUPPORTED = 1;
  ERROR_SERVICE_UNKNOWN = 2;
  ERROR_BACKEND_SPAWN_FAILED = 3;
  ERROR_RATE_LIMITED = 4;
  ERROR_SHUTTING_DOWN = 5;
  ERROR_PEER_REJECTED = 6;
  ERROR_INTERNAL = 7;
  ERROR_VERSION_BLOCKED = 8;        // version below min-supported floor
  ERROR_FD_PRESSURE = 9;            // reserved for v1.x SELF_DEMOTE
  reserved 10 to 20;
}

// Broker -> backend offer to adopt a handed-off client connection
// (#354 slice 6). Rides Frame.payload with kind = FRAME_KIND_REQUEST
// and payload_protocol = 0xD0FF (HANDOFF_PAYLOAD_PROTOCOL in code) on
// the broker<->backend control connection, mirroring how Hello (0x00),
// admin verbs (0xAD01), and endpoint probes (0xB232) ride the envelope.
message HandoffOffer {
  // Duplicated handle value as it appears in the BACKEND's handle table
  // (Windows DuplicateHandle path). Zero on Unix, where the fd travels
  // with the message via SCM_RIGHTS instead of by value.
  uint64 handle_value = 1;
  bytes token = 2;                  // 16-byte one-time handoff token
  string service_name = 3;          // service the handoff was negotiated for
  uint64 correlation_id = 4;        // request/connection correlation; echoed in HandoffAck
  reserved 5 to 10;
}

// Backend -> broker acknowledgement of a HandoffOffer. Rides
// Frame.payload with kind = FRAME_KIND_RESPONSE and
// payload_protocol = 0xD0FF on the same control connection.
message HandoffAck {
  bytes token = 1;                  // echo of HandoffOffer.token
  bool accepted = 2;                // true when the backend adopted the connection
  string error_detail = 3;          // human-readable detail when accepted = false
  uint64 correlation_id = 4;        // echo of HandoffOffer.correlation_id
  reserved 5 to 10;
}
