"""Stable exit-code constants for CLI top-level handlers.

Closes the closed-box leak around exit-code policy — without
this, every consumer CLI invented its own integer scheme and
shipped a bespoke ``except AppError`` ladder that drifted from
the library's category boundaries.

The numbering is intentionally sparse (skips between categories)
so a future bump can slot a new category without renumbering
every existing constant.

Mapping to the typed-exception hierarchy (rule EH-04):

  - :data:`EXIT_SUCCESS`            ← no exception
  - :data:`EXIT_CONFIG_ERROR`       ← :class:`ConfigError` family
  - :data:`EXIT_OPERATION_ERROR`    ← :class:`OperationError` family
  - :data:`EXIT_GUEST_ERROR`        ← :class:`GuestError` family
  - :data:`EXIT_ENVIRONMENT_ERROR`  ← :class:`HostEnvironmentError` family
  - :data:`EXIT_PROVIDER_ERROR`     ← :class:`ProviderError` family
  - :data:`EXIT_VAULT_ERROR`        ← :class:`VaultError` family
  - :data:`EXIT_APP_ERROR`          ← any other :class:`AppError`
    subclass with no more-specific category above (e.g.
    :class:`SchedulerError`, the :class:`HttpError` family). This
    base-level fallback means EVERY typed ``AppError`` exits with a
    typed code and does NOT trigger a crash report.
  - :data:`EXIT_UNKNOWN`            ← only genuinely UNTYPED
    exceptions (not an :class:`AppError`); the catch-all branch
    maps these here AND ships a crash report.

Cancellation (:class:`CancellationError`) is a subclass of
:class:`OperationError` and translates to
:data:`EXIT_OPERATION_ERROR` — consumer CLIs that want a
distinct exit code MUST pass an ``exit_code_map`` override to
:func:`run_and_translate`.

These constants are stable across the 0.x window — bumping any
of them is a breaking change (rule API-04).
"""

from __future__ import annotations

EXIT_SUCCESS = 0
"""Clean exit. The conventional Unix value."""

EXIT_CONFIG_ERROR = 1
"""Config parse / validation failure (:class:`ConfigError` and
subclasses)."""

EXIT_OPERATION_ERROR = 2
"""Runtime failure during a long-running operation
(:class:`OperationError` and subclasses, including
:class:`CancellationError` by default)."""

EXIT_GUEST_ERROR = 3
"""Failure communicating with a remote agent
(:class:`GuestError` and subclasses)."""

EXIT_ENVIRONMENT_ERROR = 4
"""Host pre-flight failure
(:class:`HostEnvironmentError` and subclasses).

NOTE: the deprecated alias :class:`EnvironmentError` shadows
Python's built-in name; this constant maps to the renamed
:class:`HostEnvironmentError` per FEEDBACK API-01."""

EXIT_PROVIDER_ERROR = 5
"""Failure inside a provider implementation
(:class:`ProviderError` and subclasses, including
:class:`ResourceNotFoundError` /
:class:`ResourceAlreadyExistsError`)."""

EXIT_VAULT_ERROR = 6
"""Credential-vault failure (:class:`VaultError` and subclasses)."""

EXIT_APP_ERROR = 7
"""A typed :class:`AppError` with no more-specific category.

The base-level fallback in :func:`run_and_translate`'s default map:
any :class:`AppError` subclass that does not resolve to one of the
six specific codes above (e.g. :class:`SchedulerError`, the
:class:`HttpError` family, or a future direct subclass) lands here.
This guarantees that a TYPED, expected failure always produces a
typed exit code and is NEVER mistaken for an internal crash — no
crash report is shipped (rule EH-04). Consumers wanting a distinct
code for a particular family pass an ``exit_code_map`` override."""

EXIT_UNKNOWN = 10
"""A genuinely UNTYPED exception (not an :class:`AppError`) escaped
to the top level. The :func:`run_and_translate` catch-all maps to
this value AND ships a crash report via
:func:`mgf.common.observability.report_now` (source ``"cli"``)."""


__all__ = [
    "EXIT_APP_ERROR",
    "EXIT_CONFIG_ERROR",
    "EXIT_ENVIRONMENT_ERROR",
    "EXIT_GUEST_ERROR",
    "EXIT_OPERATION_ERROR",
    "EXIT_PROVIDER_ERROR",
    "EXIT_SUCCESS",
    "EXIT_UNKNOWN",
    "EXIT_VAULT_ERROR",
]
