// Canonical machine-readable error reasons for TARS.
//
// Every TARS error carries a `google.rpc.ErrorInfo.reason` string in
// SCREAMING_SNAKE_CASE. On the gRPC/Connect surface the reason rides in the
// `details` of `google.rpc.Status`; on the REST surface the response-shaping
// filter projects it into the `reason` member of the RFC 7807 `Problem`
// envelope (see api/tars/common/v1/types.proto).
//
// This file is the closed registry of those reason strings. It is the
// counterpart of IA's `api/ia/errors/v1/reasons.proto`. The enum exists so the
// set is enumerable and append-only; the *wire* value is the bare reason name
// with the `ERROR_REASON_` prefix stripped -- e.g. enum value
// `ERROR_REASON_MODEL_NOT_FOUND` corresponds to the wire reason
// `MODEL_NOT_FOUND`. The canonical bare strings are mirrored as Go constants in
// `svc/internal/apierr`, which services and the default-reason interceptor use
// directly.
//
// Adding a reason is a backward-compatible change: append a new enum value with
// the next number. Removing or renumbering a value is breaking.
syntax = "proto3";

package tars.errors.v1;

option go_package = "github.com/tetrateio/fraser/api/tars/errors/v1;errorsv1";

// ErrorReason enumerates the closed set of machine-readable reasons TARS emits.
//
// The wire reason (what lands in `ErrorInfo.reason` / `Problem.reason`) is the
// value name with the `ERROR_REASON_` prefix removed.
enum ErrorReason {
  // Default / unset. Maps to the wire reason `UNKNOWN`. Used when no more
  // specific reason applies and the error code is itself non-specific.
  ERROR_REASON_UNSPECIFIED = 0;

  // The request was malformed or carried an invalid argument. Pairs with
  // connect code `invalid_argument`. Wire reason `INVALID_ARGUMENT`.
  ERROR_REASON_INVALID_ARGUMENT = 1;

  // The caller is not authenticated. Pairs with connect code
  // `unauthenticated`. Wire reason `UNAUTHENTICATED`.
  ERROR_REASON_UNAUTHENTICATED = 2;

  // The caller is authenticated but not authorized for this operation. Pairs
  // with connect code `permission_denied`. Wire reason `PERMISSION_DENIED`.
  ERROR_REASON_PERMISSION_DENIED = 3;

  // The requested resource does not exist. Pairs with connect code
  // `not_found`. Wire reason `NOT_FOUND`.
  ERROR_REASON_NOT_FOUND = 4;

  // The resource the caller tried to create already exists. Pairs with connect
  // code `already_exists`. Wire reason `ALREADY_EXISTS`.
  ERROR_REASON_ALREADY_EXISTS = 5;

  // The system is not in the required state for the operation. Pairs with
  // connect code `failed_precondition`. Wire reason `FAILED_PRECONDITION`.
  ERROR_REASON_FAILED_PRECONDITION = 6;

  // An unexpected internal error occurred. Pairs with connect code `internal`.
  // Wire reason `INTERNAL`.
  ERROR_REASON_INTERNAL = 7;

  // The service is currently unavailable; the caller may retry. Pairs with
  // connect code `unavailable`. Wire reason `UNAVAILABLE`.
  ERROR_REASON_UNAVAILABLE = 8;

  // --- Domain-specific reasons (inference / catalog / tenancy) ---

  // The requested model selector matched no catalog model. Wire reason
  // `MODEL_NOT_FOUND`.
  ERROR_REASON_MODEL_NOT_FOUND = 100;

  // A bare model name matched models under more than one provider; the caller
  // must qualify it as `provider/model`. Wire reason `MODEL_AMBIGUOUS`.
  ERROR_REASON_MODEL_AMBIGUOUS = 101;

  // The named catalog provider does not exist. Wire reason
  // `PROVIDER_NOT_FOUND`.
  ERROR_REASON_PROVIDER_NOT_FOUND = 102;

  // The caller attempted to act on a (customer, project) tuple they are not a
  // member of. Wire reason `CROSS_TENANT_DENIED`.
  ERROR_REASON_CROSS_TENANT_DENIED = 103;

  // The caller omitted a required tenancy field (customer_id / project_id) and
  // no session default could be resolved from their memberships. Wire reason
  // `SESSION_DEFAULT_UNRESOLVED`.
  ERROR_REASON_SESSION_DEFAULT_UNRESOLVED = 104;
}
