//! sv-axis (`session_version`) enforcement port + first-party adapters.
//!
//! Phase 11.Z (RFC_2026-05-09 §3.5 Row 4*/5*) — the SDK boundary's
//! re-export of the engine's `EpochRevocation` port plus the canonical
//! adapter set consumers wire at boot:
//!
//! - [`Cache`] / [`Fetcher`] — narrow port traits (promoted from
//!   chat-auth's `validator.rs` `SessionVersionCache` / `SessionVersionFetcher`
//!   pair under §3 Row 6 "replace, don't layer").
//! - [`InProcessTtlCache`] — opinionated [`Cache`] impl (per-pod TTL map).
//! - [`SharedCacheCache`] (gated `feature = "shared-cache"`) — adapter
//!   bridging `ppoppo_infra::Cache` (KVRocks via the canonical
//!   `STANDARDS_SHARED_CACHE.md §3.1` `sv:{sub}` namespace) to
//!   [`Cache`]. RFC_2026-05-08 §4.1 lock — promoted from chat-api's
//!   `session_version::KvCache` adapter (replace, don't layer).
//! - [`CompositeEpochRevocation`] — combines a [`Cache`] + a [`Fetcher`]
//!   into the engine port. Cache hit short-circuits; cache miss fetches
//!   authoritative + writes back. Fetcher transient surfaces as
//!   [`EpochRevocationError::Transient`], engine maps to
//!   [`AuthError::SessionVersionLookupUnavailable`], SDK maps to
//!   [`crate::token::VerifyError::SessionVersionLookupUnavailable`].
//!
//! ## 0.10.0 BREAKING — `UserinfoFetcher` removed
//!
//! `UserinfoFetcher` was deleted in 0.10.0 (RFC_2026-05-08 §4.3 lock).
//! The 0.9.0 framing was misleading — PAS's userinfo authenticates the
//! *caller*, not an arbitrary queried subject, so `Fetcher::fetch(sub)`
//! ignored `_sub`. Zero consumers across the workspace verified
//! 2026-05-08. Replacement for per-user sv readout: [`SharedCacheCache`]
//! over the canonical KVRocks `sv:{sub}` key (proper per-user shape).
//! Cache-miss fetcher choice is consumer-specific — see RFC_2026-05-08
//! §4.4 for Slice 3 deferred options (cache-only fail-closed, PAS
//! per-user readout endpoint, or engine relax).
//!
//! ## Why HIDDEN sv on `Claims`, surfaced via the cache substrate
//!
//! The engine deliberately HIDES `sv` on `Claims` (Phase 4 Decision 1,
//! `ppoppo_token::access_token::claims`). Surfacing the *token's* sv
//! would push enforcement onto every caller. The cache substrate
//! reflects the *current authoritative value*, not the token's claim —
//! a different role. Consumers wiring this module never see the token's
//! sv; they hand authoritative-substrate lookups to the engine via
//! [`crate::PasJwtVerifier::with_epoch_revocation`].
//!
//! See `0context/RFC_2026-05-09_pas-external-0.9.0-sv-axis-surfacing.md`
//! §3 + §3.5 + §4 for the full architecture frame, and
//! `0context/RFC_2026-05-08_pas-external-0.10.0-rcw-ctw-sv-axis-completion.md`
//! §4 for the 0.10.0 SDK shape locks.
//!
//! [`AuthError::SessionVersionLookupUnavailable`]: ppoppo_token::access_token::AuthError::SessionVersionLookupUnavailable

mod cache;
mod composite;
mod fetcher;
#[cfg(feature = "shared-cache")]
mod shared_cache;
mod ttl_cache;

pub use cache::Cache;
pub use composite::CompositeEpochRevocation;
pub use fetcher::{FetchError, Fetcher};
#[cfg(feature = "shared-cache")]
pub use shared_cache::SharedCacheCache;
pub use ttl_cache::InProcessTtlCache;

// Engine port re-export. The textbook deep module: small interface
// (`current(sub) -> Result<i64, _>`), large implementation
// (`engine::check_epoch::run` — R6 legacy admit, transient mapping,
// M37 observability, raw-payload sv extraction). Re-exporting here
// lets consumers depend only on `pas-external` without a transitive
// `ppoppo-token` Cargo entry.
pub use ppoppo_token::access_token::{EpochRevocation, EpochRevocationError};

// Shared key shape constants. PAS writes `sv:{sub}` to the canonical
// shared cache; consumers reading the same key share the namespace.
// SSOT lives in `ppoppo-token` so PAS writer and SDK consumer cannot
// drift.
pub use ppoppo_token::{SV_CACHE_TTL, sv_cache_key};
