mod.rs

This Kit feature is not available yet.

In rust/crates/mkit-server/src/pipeline/At c3d562f

c3d562fHistory

Preview

Code189.3 KiB
//! The transport-neutral request pipeline (PRD §5.4): the unary RPCs of
//! `mkit.transport.v1` over the storage contract.
//!
//! A binding calls [`Pipeline::authenticate`] (stages 0 and 1) from its
//! interceptor, then one entry point. A signed write runs one function per
//! stage, in order: `identify` (stage 1), `replay_lookup` (the stage 0
//! lookup), `authorize` (2), `admit` (3), `pre_receive` (5) and
//! `plan_and_apply` (4 and 6, one batch). Admission receipts are attached
//! only to a committed response; durable outcomes are queued for delivery.
//! The streaming procedures are [`Pipeline::open_upload`]
//! ([`UploadSession`]) and [`Pipeline::download`] ([`DownloadStream`]).
//!
//! With the `__test-faults` feature, `Pipeline::with_faults` installs
//! `FaultHooks` and [`Pipeline::authenticate`] reads per-request
//! `TestDirectives`; without it none of that exists in the binary.
//!
//! `Bearer`/`Open` support packmap-then-head on a non-atomic store without
//! replay or quota. `AuthV2` supports a replay ledger, per-signer quota and
//! atomic advance. `mkit serve` over SSH uses `TransportIdentity`.

mod admission;
mod advance;
mod auth;
mod authority;
mod begin;
pub mod clearance;
mod coordinator;
mod download;
mod durable_outcome;
mod embedded;
mod epoch;
#[cfg(feature = "__test-faults")]
pub(crate) mod faults;
mod fork_op;
mod gate;
mod hooks;
#[cfg(feature = "http-objects")]
mod http;
#[cfg(feature = "http-objects")]
mod http_admission;
#[cfg(feature = "http-objects")]
mod http_tokens;
#[cfg(feature = "http-objects")]
mod object_reader;
mod pending_hold;
mod published_source;
#[cfg(feature = "http-objects")]
mod read_limits;
#[cfg(feature = "http-objects")]
pub(crate) mod read_proofs;
#[cfg(feature = "http-objects")]
mod reader_checks;
#[cfg(feature = "http-objects")]
pub use crate::HistoryStateLimit;
#[cfg(feature = "http-objects")]
pub use object_reader::{
    CommitPathRead, ContinuedHistoryOptions, ContinuedHistoryOrder, ContinuedHistoryPage,
    HistoryCommit, HistoryContinuation, HistoryContinuationState, HistoryMode, HistoryOptions,
    HistoryPage, IssuedUrl, OBJECT_READER_BATCH, OBJECT_READER_CALLS, OBJECT_READER_LIMIT_MESSAGE,
    ObjectMetadata, ObjectReader, PathOptions, PathTree, PathWitness, ReaderView,
};
#[cfg(feature = "http-objects")]
pub use read_limits::{ReadLimits, ReaderSession};
#[cfg(feature = "http-objects")]
pub use read_proofs::CaptureCheckpoint;
mod implicit;
mod info;
mod repo_storage;
pub use repo_storage::{MAX_REPO_STORAGE_BATCH, RepoStorage};
#[cfg(feature = "remote-hooks")]
pub mod inspection;
mod lease;
pub mod list;
mod list_repos;
pub(crate) use list_repos::index_writes as list_repos_index_writes;
pub use list_repos::{RepoEntry, RepoPage};
mod outcome;
mod parts;
mod plan;
pub(crate) use plan::{Snapshot as PlanSnapshot, epoch_moved, plan_charge};
pub(crate) mod publication_budget;
mod purge;
mod ref_policy;
mod reservation;
mod revocation;
mod scanner_retrieval;
mod shard;
mod staging;
#[cfg(test)]
mod tests;
mod typed_reads;
mod upload;
mod visibility_hooks;
mod watermark;

use core::future::Future;
use core::time::Duration;
use std::sync::Arc;

pub use mkit_attest::grant::Visibility as RepoVisibility;
use mkit_attest::grant::{Visibility, verify_visibility_statement};
use mkit_core::hash::{Hash, to_hex, to_hex_bytes};
use mkit_core::protocol::{AdvanceOutcome, PackKey};
use mkit_core::repo_identity::{Namespace, RepositoryIdentity};
use mkit_core::write_auth::MAX_CLOCK_LEAD_MS;
use tracing::Instrument;

use crate::download::DOWNLOAD_CHUNK_MAX;
use crate::error::{AbortCause, InvalidHeader, ServerError};
use crate::op::{
    AuthzFacts, CallerView, GrantRef, OpKind, Operation, Procedure, RefUpdate, VerifiedAuth,
};
use crate::policy::ff::FastForward;
use crate::policy::{
    AuthorizerRole, GrantConfig, NamespacePolicy, WritePolicy, grants, read as read_policy,
};
use crate::principal::Principal;
use crate::quota::{
    self, DEFAULT_WRITE_QUOTA, NamespaceCharge, NamespaceDecision, NamespaceView, QuotaCharge,
    QuotaLimits, QuotaScope, ViewStatus,
};
use crate::refs::{self, strip_listed_prefix, validate_ref_name};
use crate::replay::{
    BeginUploadResult, ReplayDecision, ReplayRecord, ReplayState, StoredResult, UpdateRefResult,
    classify,
};
use crate::repo::{Addressing, RepoId};
use crate::rt::Clock;
use crate::storage_error::{StorageOp, describe_and_map};
use crate::store::tickets::TicketCaps;
use crate::store::{
    Batch, BatchOutcome, Key, KeyClasses, MAX_BATCH_OPS, MultipartBlobStore, NamespaceStore,
    Partition, Precondition, StoreError, Value, codec, keys, read,
};
use crate::telemetry::{Metrics, Redactor};
use crate::upload::{UploadLimits, token::TicketKeys};
use crate::url_token::{MintedToken, UrlTarget};
use begin::BeginWrite;

#[cfg(feature = "remote-hooks")]
pub(crate) use admission::validate_decision;
pub use auth::{AuthMode, Authenticated, HeaderValues, RequestMeta};
pub use download::{DownloadChunk, DownloadStream};
pub use durable_outcome::{DeliveryError, Outcome, OutcomeKind};
pub use embedded::{EmbeddedGate, EmbeddedProcedure, Fork as EmbeddedFork, NoGate};
#[cfg(feature = "__test-faults")]
pub use faults::{
    BUMP_EPOCH_HEADER, CLOCK_SKEW_HEADER, FAULT_HEADER, FailOnce, FaultHooks, FaultPoint,
    LEASE_RECOVERED_HEADER, RELAY_DELAY_MS_HEADER, RUN_TIMERS_HEADER, TIMER_MS_HEADER,
    TestDirectives,
};
pub use hooks::{
    ADMISSION_EXPOSE_HEADERS, Admission, AdmissionDecision, AdmissionInput, Authorizer, Challenge,
    Choice, CredentialHeader, DefaultAdmission, ForkAdmission, HookSet, Hooks, NoOutcomes,
    NoPreReceive, NoReceipts, OpenAuthorizer, OutcomeSink, PreReceive, ReceiptSigner, RefEffect,
    ResolvedRefUpdate,
};
#[cfg(feature = "ssh")]
pub(crate) use implicit::IMPLICIT_PACKMAP_UNKNOWN;
pub(crate) use implicit::PendingPack;
pub use info::ServerInfo;
pub use lease::{LeaseParams, renew_for_relay};
use outcome::Outcome as RequestOutcome;
pub use parts::PartUploadSession;
use plan::{
    ImplicitConsume, MAX_REPLAN, PRUNE_LIMIT, Plan, PlanClock, Planned, Snapshot, WriteKind,
    WriteRequest, plan_write, prune_sampled,
};
pub use revocation::{MAX_EPOCH_STEP, RevokeBudget, RevokeProgress};
#[cfg(test)]
pub(crate) use shard::WideRepoIndexShards;
pub use shard::{D34Shards, ShardMap, SinglePartition};
pub use upload::{UploadMode, UploadSession};

/// Success-only headers returned by admission. They are best-effort and are
/// never stored in the signed replay ledger or returned on a replay.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ResponseMeta {
    headers: Vec<(String, String)>,
    external_ref: Option<String>,
}

impl ResponseMeta {
    /// Headers in admission order, followed by the private cache directive.
    #[must_use]
    pub fn headers(&self) -> &[(String, String)] {
        &self.headers
    }
    /// Hook reference carried for the later storage receipt integration.
    #[must_use]
    pub fn external_ref(&self) -> Option<&str> {
        self.external_ref.as_deref()
    }
}

/// Call the installed fault hooks at a fault point, returning early on
/// their error. Compiled out without `__test-faults`.
macro_rules! fault {
    ($pipe:expr, $point:ident, $op:expr, $a:expr) => {
        #[cfg(feature = "__test-faults")]
        $pipe
            .fault($crate::pipeline::FaultPoint::$point, $op, $a)
            .await?
    };
}
pub(crate) use fault;

/// Default bound from planning a batch to its commit (00-plan P-21,
/// SPEC-WRITE-GRANTS §5.5). It MUST exceed the clock skew between the
/// planner and the storage backend (Worker isolate vs Durable Object on
/// Workers; zero natively) plus the longest synchronous span before the
/// commit, by a wide margin: a batch that misses it commits nothing.
pub const MAX_APPLY_WINDOW: Duration = Duration::from_secs(10);

// A signed write's deadline is capped at `expires_at + MAX_CLOCK_LEAD_MS`
// (see `plan_clock`). That stays below the replay prune grace, so a stalled
// duplicate can never commit after its record could have been pruned.
const _: () = assert!(MAX_CLOCK_LEAD_MS.unsigned_abs() < read::REPLAY_PRUNE_GRACE_MS);

/// Default `ListRefs` scan page.
pub const DEFAULT_LIST_PAGE_LIMIT: u32 = 1000;

/// Counter: a write failed because its partition is full (00-plan P-24).
/// Label `kind`; alert on any increase.
pub const METRIC_PARTITION_FULL: &str = "mkit_server_partition_full_total";

/// Counter: [`Pipeline::with_header`] dropped an invalid or reserved
/// header; label `reason` (`name`, `reserved`, `value`).
pub const METRIC_HEADER_DROPPED: &str = "mkit_server_error_header_dropped_total";

/// Deployment routing for repository state.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum Sharding {
    /// All rows of a namespace share one partition.
    #[default]
    Single,
    /// Coordinator and per-branch ref shards (D34).
    D34,
}

fn require_relay_source_lease(
    sharding: Sharding,
    has_lease: bool,
    batch: &Batch,
) -> Result<(), ServerError> {
    if sharding == Sharding::D34
        && !has_lease
        && batch.writes.iter().any(|write| {
            matches!(write, crate::store::Write::Put(key, _) if matches!(keys::parse(key), Some(keys::ParsedKey::Relay(_))))
        })
    {
        return Err(internal("D34 relay batch lacks source epoch lease"));
    }
    Ok(())
}

/// What `authorize_read` established: the caller's facts (including its
/// §10.1 view) and the stored grant epoch it checked a presented grant
/// against.
#[derive(Debug)]
struct ReadAuth {
    /// Facts threaded into `op.authz` for the hooks.
    facts: AuthzFacts,
    /// The coordinator's `e` row, `0` when absent; `None` when
    /// visibility does not apply and no epoch was read. `IssueObjectUrl`
    /// reuses it.
    epoch: Option<u64>,
}

/// A deployment's pipeline settings. Start from [`PipelineConfig::new`].
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct PipelineConfig {
    /// How requests map to a repository (M0: `Single`).
    pub addressing: Addressing,
    /// Namespace trust model; self-certifying by default.
    pub namespace_mode: crate::namespace::NamespaceMode,
    /// How metadata partitions are routed.
    pub sharding: Sharding,
    /// How requests authenticate.
    pub auth: AuthMode,
    /// Owner-signed write grant verifier for Multi/Owner deployments.
    pub grants: Option<GrantConfig>,
    /// Independent deployment-authority fence, optional and default-off.
    pub authority_fence: Option<crate::authority::AuthorityFence>,
    /// Write authorization policy; Open for Single, Owner for Multi.
    pub write_policy: WritePolicy,
    /// Visibility of repositories without an explicit stored setting (default public).
    pub default_repo_visibility: RepoVisibility,
    /// Role of the authorizer hook, defaulting to an additional check.
    pub authorizer_role: AuthorizerRole,
    /// Opt in to namespace-wide `ListRepos` authority grants, requiring returned writer view.
    /// Default false: non-owner authority callers receive only the public listing.
    pub list_repos_authority_full: bool,
    /// Upload caps, supplied by the binding (used by M0-05b).
    pub upload_limits: UploadLimits,
    /// Optional tighter cap for legacy single-part `UploadPack` requests.
    pub single_upload_max_bytes: Option<u64>,
    /// Resumable upload part size: a power of two in 8–32 MiB.
    pub part_size: u64,
    /// Largest number of parts, sufficient to reach the upload byte cap.
    pub max_parts: u32,
    /// Largest requested `ListRefs` page, in 1..=10,000. The default 1000
    /// refs with at most 512-byte names fit STC §7.9's 2 MiB page bound.
    pub max_list_refs_page_size: u32,
    /// Packs smaller than this may skip `BeginUpload`; `u64::MAX` means never
    /// required. Advertised as zero with Multi addressing or admission.
    pub begin_upload_threshold_bytes: u64,
    /// Accepted deployment upload MAC keys; first key signs.
    pub ticket_keys: Option<TicketKeys>,
    /// Default-off private raw-pack scanner retrieval, with dedicated keys.
    pub scanner_retrieval: Option<Arc<crate::scanner_retrieval::RetrievalConfig>>,
    /// URL-token key set and lifetime for `IssueObjectUrl`
    /// (SPEC-WRITE-GRANTS §9.4); `None` answers `unimplemented`.
    pub url_tokens: Option<crate::url_token::UrlTokenConfig>,
    /// Dedicated selected-ref structural continuations; disabled by default.
    pub history_tokens: Option<crate::history_token::HistoryTokenConfig>,
    /// Dedicated role keys, forbidden for client and owner authorization.
    pub admin_keys: Vec<[u8; 32]>,
    /// Receipt role key publication required by enabled takedown, without issuing receipts.
    pub receipt_publication: Option<crate::takedown::PublicationConfig>,
    /// Durable invalidation; absent keeps launch purge machinery inert.
    pub purge: Option<crate::purge::PurgeConfig>,
    /// Ticket lifetime, positive and strictly below seven days.
    pub ticket_ttl_ms: u64,
    /// Open-ticket bounds in each ref shard.
    pub ticket_caps: TicketCaps,
    /// Largest download chunk (used by M0-05b).
    pub download_chunk_max: usize,
    /// The default write quota: `Some(DEFAULT_WRITE_QUOTA)` for auth v2
    /// deployments. Under sharding it counts per ref shard;
    /// Multi-addressing deployments also use it as the default namespace cap.
    pub write_quota: Option<QuotaLimits>,
    /// `ListRefs` scan page size, at least 1.
    pub list_page_limit: u32,
    /// Commit deadline window; see [`MAX_APPLY_WINDOW`].
    pub max_apply_window: Duration,
    /// Coordinator epoch lease duration, in milliseconds.
    pub epoch_lease_ms: u64,
    /// Safety margin in milliseconds. It must exceed the maximum clock skew
    /// between every pipeline instance (grant, renewal and revoke), the sweep
    /// driver, and every storage backend. The constructor cannot verify this.
    pub lease_margin_ms: u64,
    /// Minimum useful lease budget before renewing, in milliseconds.
    pub min_lease_budget_ms: u64,
    /// Extra header names never to log.
    pub redactor: Redactor,
    /// Extra request credential names passed to admission, in addition to payment defaults.
    pub admission_credential_headers: Vec<String>,
    /// Soft per-shard cap on undelivered outcomes, events and purges.
    pub outbox_backlog_cap: Option<OutboxBacklogCap>,
    /// Indexed ingestion and pre-receive verification, off by default.
    pub indexed: Option<crate::indexed::IndexedConfig>,
    /// Global takedown denial, including object, pack and reconstruction-base checks.
    /// When disabled, ingest and reads omit block and denial-action rows, and
    /// this pipeline cannot authorize denial activation. Enabling it on an
    /// existing store requires the inventory, holder and proof migration.
    pub takedown_denial: bool,
    /// Per-ref allowed signers and fast-forward-only rules (SPEC-SERVER
    /// §9.7). Native embedders and the Worker launch can configure them. A
    /// fast-forward-only rule needs `indexed`.
    pub ref_policy: Option<crate::policy::RefPolicy>,
    /// HTTP object serving (SPEC-HTTP-OBJECTS), off by default and
    /// explicitly configured by the adapter. Requires [`Self::indexed`].
    #[cfg(feature = "http-objects")]
    pub http_objects: Option<crate::http_objects::HttpObjectsConfig>,
}

/// A soft, unguarded backlog threshold; concurrent admissions may overshoot
/// by at most their in-flight terminal rows and encoded bytes.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct OutboxBacklogCap {
    /// Terminal/event/purge rows.
    pub rows: u64,
    /// Key plus encoded-value bytes.
    pub bytes: u64,
}

impl OutboxBacklogCap {
    /// Construct explicit deployment settings; fields may be adjusted before use.
    #[must_use]
    pub const fn new(rows: u64, bytes: u64) -> Self {
        Self { rows, bytes }
    }
}

impl PipelineConfig {
    /// One seam for advertised and enforced indexed mode.
    pub(crate) fn indexed_mode(&self) -> bool {
        self.indexed.is_some()
    }

    /// Defaults for `auth`: the default write quota only for auth v2.
    #[must_use]
    pub fn new(addressing: Addressing, auth: AuthMode, upload_limits: UploadLimits) -> Self {
        let write_quota = matches!(auth, AuthMode::AuthV2(_)).then_some(DEFAULT_WRITE_QUOTA);
        let write_policy = match &addressing {
            Addressing::Single { .. } => WritePolicy::Open,
            Addressing::Multi(_) => WritePolicy::Owner,
        };
        Self {
            write_policy,
            default_repo_visibility: RepoVisibility::Public,
            authorizer_role: AuthorizerRole::Check,
            list_repos_authority_full: false,
            addressing,
            namespace_mode: crate::namespace::NamespaceMode::SelfCertifying,
            sharding: Sharding::Single,
            auth,
            grants: None,
            authority_fence: None,
            upload_limits,
            single_upload_max_bytes: None,
            part_size: mkit_core::upload_parts::MIN_PART_SIZE,
            max_parts: 10_000,
            max_list_refs_page_size: DEFAULT_LIST_PAGE_LIMIT,
            begin_upload_threshold_bytes: u64::MAX,
            ticket_keys: None,
            scanner_retrieval: None,
            url_tokens: None,
            history_tokens: None,
            admin_keys: Vec::new(),
            receipt_publication: None,
            purge: None,
            ticket_ttl_ms: 86_400_000,
            ticket_caps: TicketCaps::new(1024, 64),
            download_chunk_max: DOWNLOAD_CHUNK_MAX,
            write_quota,
            list_page_limit: DEFAULT_LIST_PAGE_LIMIT,
            max_apply_window: MAX_APPLY_WINDOW,
            epoch_lease_ms: 30_000,
            lease_margin_ms: 5_000,
            min_lease_budget_ms: 1_000,
            redactor: Redactor::default(),
            admission_credential_headers: Vec::new(),
            outbox_backlog_cap: Some(OutboxBacklogCap::new(100_000, 64 * 1024 * 1024)),
            indexed: None,
            takedown_denial: false,
            ref_policy: None,
            #[cfg(feature = "http-objects")]
            http_objects: None,
        }
    }

    /// Validate the namespace trust model and dedicated authority scopes at startup.
    /// # Errors
    /// Inconsistent addressing, hook role, fence, policy, or authority key roles.
    pub fn validate_namespace_mode(&self) -> Result<(), ServerError> {
        if self.namespace_mode == crate::namespace::NamespaceMode::Authority
            && (self.authority_fence.is_none()
                || self.authorizer_role != AuthorizerRole::Authority
                || !matches!(&self.addressing, Addressing::Multi(multi) if matches!(multi.namespace_policy, NamespacePolicy::Any { .. })))
        {
            return Err(ServerError::invalid_argument(
                "authority namespace mode requires Multi, an Authority hook, authority fencing and namespace_policy any",
            ));
        }
        if let Some(fence) = &self.authority_fence {
            fence.validate_mode(self.namespace_mode)?;
            if self.namespace_mode == crate::namespace::NamespaceMode::Authority
                && fence
                    .public_keys()
                    .any(|key| self.admin_keys.contains(&key))
            {
                return Err(ServerError::invalid_argument(
                    "authority keys must differ from admin and publication keys",
                ));
            }
            if self.namespace_mode == crate::namespace::NamespaceMode::Authority
                && fence.public_keys().any(|key| {
                    self.url_tokens.as_ref().is_some_and(|tokens| {
                        tokens.keys().public_keys().any(|public| public == key)
                    })
                })
            {
                return Err(ServerError::invalid_argument(
                    "authority keys must differ from URL-token keys",
                ));
            }
        }
        Ok(())
    }

    /// The namespace policy advertised by `GetServerInfo` (STC §2.1).
    #[must_use]
    pub fn advertised_namespace_policy(&self) -> &'static str {
        match &self.addressing {
            Addressing::Single { .. } => "single-repository",
            Addressing::Multi(multi) => match &multi.namespace_policy {
                NamespacePolicy::Allowlist(_) => "allowlist",
                NamespacePolicy::Any { .. } => "any",
            },
        }
    }
}

/// What the pipeline offers bindings and `GetServerInfo`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct PipelineCapabilities {
    /// Storage leases are supported by this pipeline (currently false).
    pub leases: bool,
    /// `AdvanceRefs` commits head and packmap in one batch.
    pub atomic_advance: bool,
}

/// [`Pipeline::health`]: whether each store answered its probe.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HealthStatus {
    /// The blob store.
    pub blobs: bool,
    /// The metadata store.
    pub meta: bool,
}

impl HealthStatus {
    /// Both stores are healthy.
    #[must_use]
    pub fn is_healthy(&self) -> bool {
        self.blobs && self.meta
    }
}

/// One `ListRefs` entry.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RefEntry {
    /// The name with the requested prefix stripped (SPEC-REFS §4).
    pub name: String,
    /// The object id.
    pub id: Hash,
}

/// A `SetRepoVisibility` request: the signed envelope's choice or the
/// unsigned owner-signed statement (SPEC-WRITE-GRANTS §9.1).
#[derive(Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum VisibilityRequest {
    /// Envelope mode: the signed request's `visibility`.
    Envelope(Visibility),
    /// `signed_statement` mode: the encoded `scheme:statement:blob` header.
    Statement(String),
}

impl core::fmt::Debug for VisibilityRequest {
    /// Never shows the raw statement.
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::Envelope(visibility) => f.debug_tuple("Envelope").field(visibility).finish(),
            Self::Statement(statement) => f
                .debug_tuple("Statement")
                .field(&format_args!("<{} bytes>", statement.len()))
                .finish(),
        }
    }
}

/// The request pipeline over blobs `B`, metadata `N` and hooks `H`.
pub struct Pipeline<B, N, H = Hooks> {
    publication_policy: Option<Arc<dyn clearance::PublicationPolicy>>,
    #[cfg(feature = "remote-hooks")]
    inspectors: Vec<Arc<dyn inspection::ContentInspector>>,
    #[cfg(feature = "remote-hooks")]
    inspect_limit: usize,
    blobs: B,
    meta: N,
    hooks: H,
    shards: Arc<dyn ShardMap>,
    cfg: PipelineConfig,
    clock: Arc<dyn Clock>,
    metrics: Arc<dyn Metrics>,
    #[cfg(feature = "__test-faults")]
    faults: Option<Arc<dyn faults::DynFaultHooks>>,
    #[cfg(feature = "__test-faults")]
    test_timer_gate: Option<Arc<tokio::sync::Mutex<()>>>,
    gate: Option<Arc<gate::WriteGate>>,
    pending_hold: Option<pending_hold::PendingHold>,
    #[cfg(feature = "http-objects")]
    http_seams: Option<crate::http_objects::HttpSeams>,
}

/// The multipart session of a ticket a committed `BeginUpload` replaced,
/// aborted by the caller after the write gate is released.
type ReplacedSession = std::sync::Mutex<Option<(crate::store::BlobKey, Vec<u8>)>>;

struct WriteInputs<'a> {
    resolved_ref_updates: &'a [ResolvedRefUpdate],
    replaced: &'a ReplacedSession,
    denial_ids: &'a std::collections::BTreeSet<Hash>,
    denial_packs: &'a [Hash],
    pending: Option<&'a reservation::PendingGuard>,
    implicit: Option<&'a [PendingPack]>,
    external_bases: &'a std::collections::BTreeSet<Hash>,
    inspected: Option<&'a mut crate::indexed::inspection::InspectionSet>,
}

impl<B, N, H> core::fmt::Debug for Pipeline<B, N, H> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("Pipeline")
            .field("cfg", &self.cfg)
            .finish_non_exhaustive()
    }
}

/// A fixed-message `internal` whose detail only the server logs.
fn internal(detail: &'static str) -> ServerError {
    ServerError::internal("ref store request failed", detail)
}

/// Map a storage failure to a redacted `internal` and log its detail.
fn store_error(op: StorageOp, err: StoreError) -> ServerError {
    if matches!(err, StoreError::TakedownDenialDisabled) {
        return ServerError::failed_precondition("takedown denial disabled");
    }
    let op = match err {
        StoreError::Corrupt(_) | StoreError::MalformedReply(_) => StorageOp::MetaDecode,
        _ => op,
    };
    let (line, err) = describe_and_map(op, err);
    tracing::warn!(detail = %line, "storage failure");
    err
}

fn meta_error(err: StoreError) -> ServerError {
    store_error(StorageOp::MetaCall, err)
}

/// The Connect method name, e.g. `UpdateRef`: the `procedure` label.
fn method(procedure: Procedure) -> &'static str {
    let path = procedure.connect_path();
    path.rsplit('/').next().unwrap_or(path)
}

/// Stage 0 lookup's answer for a replay decision: `None` continues.
fn replay_answer(decision: ReplayDecision) -> Result<Option<StoredResult>, ServerError> {
    match decision {
        ReplayDecision::New => Ok(None),
        ReplayDecision::Return(result) => Ok(Some(result)),
        ReplayDecision::FingerprintMismatch => Err(ServerError::invalid_argument(
            "nonce reused for a different operation",
        )),
        // `Resume` is for `UploadPack` only (M0-05b); a unary write that
        // finds its record in flight waits like any other.
        ReplayDecision::RetryLater | ReplayDecision::Resume => Err(ServerError::aborted_retryable(
            "operation already in flight; retry",
        )),
    }
}

fn ms(ms: i64) -> u64 {
    u64::try_from(ms).unwrap_or(0)
}

/// Resolve visibility for reads and snapshot publication. Explicit rows always
/// override the deployment default; callers strongly read the row, never cache it.
#[must_use]
pub fn repo_is_private(stored: Option<&codec::RepoVisibilityV1>, default: RepoVisibility) -> bool {
    stored.map_or(default == RepoVisibility::Private, |row| {
        row.visibility == codec::StoredVisibility::Private
    })
}

/// The `rv` codec's visibility for a statement/envelope [`Visibility`].
fn stored_visibility(visibility: Visibility) -> codec::StoredVisibility {
    match visibility {
        Visibility::Public => codec::StoredVisibility::Public,
        Visibility::Private => codec::StoredVisibility::Private,
    }
}

fn validate_upload_ticket_config<H: HookSet>(
    cfg: &PipelineConfig,
    hooks: &H,
) -> Result<(), ServerError> {
    // Transport identity carries no tickets: the ssh and enc transports
    // earn pack membership implicitly (WP-1.15's session pending set), so
    // neither the Multi refusal nor the ticket threshold applies to it.
    if cfg.begin_upload_threshold_bytes != u64::MAX
        && !matches!(cfg.auth, AuthMode::TransportIdentity)
        && (!matches!(cfg.auth, AuthMode::AuthV2(_)) || cfg.ticket_keys.is_none())
    {
        return Err(ServerError::invalid_argument(
            "a ticket threshold requires auth v2 and upload ticket keys",
        ));
    }
    if !matches!(cfg.auth, AuthMode::TransportIdentity)
        && !hooks.admission().is_default()
        && (!matches!(cfg.auth, AuthMode::AuthV2(_)) || cfg.ticket_keys.is_none())
    {
        return Err(ServerError::invalid_argument(
            "admission requires auth v2 and upload ticket keys",
        ));
    }
    if matches!(cfg.addressing, Addressing::Multi(_))
        && matches!(cfg.auth, AuthMode::AuthV2(_))
        && cfg.ticket_keys.is_none()
    {
        return Err(ServerError::invalid_argument(
            "multi-repository auth v2 deployments require upload ticket keys",
        ));
    }
    Ok(())
}

impl<B: MultipartBlobStore, N: NamespaceStore, H: HookSet> Pipeline<B, N, H> {
    /// Permission to install denial rows when deployment denial is enabled.
    #[must_use]
    pub fn denial_capability(&self) -> Option<crate::takedown::DenialCapability> {
        self.cfg
            .takedown_denial
            .then(crate::takedown::DenialCapability::enabled)
    }

    /// The deployment namespace grammar used to resolve request routes.
    #[must_use]
    pub fn namespace_mode(&self) -> crate::namespace::NamespaceMode {
        self.cfg.namespace_mode
    }

    /// A pipeline over `blobs` and `meta`, routed by `cfg.sharding`.
    ///
    /// # Errors
    /// `invalid_argument` for a configuration the store cannot serve: auth
    /// v2 needs every key class and atomic multi-key batches (so
    /// `FsLayoutStore` never runs auth v2); a store without atomic batches
    /// must report an implicit layout version; a store's layout version
    /// must be this binary's; the page limit and apply window must be
    /// positive. Resumable upload and advertised page limits must be valid
    /// and the part capacity must reach the upload byte cap. Namespace/write
    /// policy combinations must be compatible;
    /// `any` requires non-default admission or its explicit unsafe override,
    /// and an authority authorizer must not be the open default.
    #[allow(clippy::too_many_lines)] // Startup rejects incompatible storage, auth and grant combinations together.
    pub fn new(
        blobs: B,
        meta: N,
        hooks: H,
        mut cfg: PipelineConfig,
        clock: Arc<dyn Clock>,
        metrics: Arc<dyn Metrics>,
    ) -> Result<Self, ServerError> {
        if let Some(publication) = &cfg.receipt_publication {
            if cfg.indexed.is_none() {
                return Err(ServerError::invalid_argument(
                    "takedown requires indexed mode",
                ));
            }
            cfg.admin_keys.extend_from_slice(publication.public_keys());
        }
        cfg.validate_namespace_mode()?;
        crate::scanner_retrieval::service::validate_config(&cfg)?;
        if let Some(purge) = &cfg.purge {
            purge.validate().map_err(meta_error)?;
        }
        if cfg.authority_fence.is_some()
            && (cfg.authorizer_role != AuthorizerRole::Authority
                || hooks.authorizer().is_open()
                || !meta.capabilities().atomic_multi_key
                || !matches!(cfg.auth, AuthMode::AuthV2(_))
                || !matches!(cfg.addressing, Addressing::Multi(_)))
        {
            return Err(ServerError::invalid_argument(
                "authority fencing requires Multi, auth v2, an Authority hook and transactional storage",
            ));
        }
        // Collapsible only when `http-objects` is off.
        #[allow(clippy::collapsible_if)]
        if let Some(fence) = &cfg.authority_fence {
            if fence.public_keys().any(|key| {
                cfg.ticket_keys
                    .as_ref()
                    .is_some_and(|tickets| tickets.contains_ed25519_public(&key))
            }) {
                return Err(ServerError::invalid_argument(
                    "authority keys must differ from ticket keys",
                ));
            }
            #[cfg(feature = "http-objects")]
            if fence.public_keys().any(|key| {
                cfg.url_tokens
                    .as_ref()
                    .is_some_and(|tokens| tokens.keys().public_keys().any(|public| public == key))
            }) {
                return Err(ServerError::invalid_argument(
                    "authority keys must differ from URL-token keys",
                ));
            }
        }
        if cfg.takedown_denial && cfg.indexed.is_none() {
            return Err(ServerError::invalid_argument(
                "takedown denial requires indexed mode",
            ));
        }
        if let Some(indexed) = &cfg.indexed {
            if !matches!(cfg.auth, AuthMode::AuthV2(_))
                || cfg.ticket_keys.is_none()
                || !matches!(cfg.addressing, Addressing::Multi(_))
            {
                return Err(ServerError::invalid_argument(
                    "indexed mode requires auth v2, ticket keys, zero ticket threshold, and Multi addressing",
                ));
            }
            if indexed.max_delta_chain_depth == 0
                || indexed.max_delta_chain_depth > u32::from(u16::MAX)
                || indexed.max_pack_bytes == 0
                || indexed.max_pack_bytes > indexed.decode_budget
                || indexed.relay_lag_bound_ms == 0
                || indexed.extract_min_bytes == 0
                || indexed.max_ancestry_commits == 0
                || indexed.max_ancestry_commits > crate::indexed::MAX_ANCESTRY_COMMITS_LIMIT
                || indexed
                    .max_extract_bytes
                    .is_some_and(|max| max < indexed.max_pack_bytes)
            {
                return Err(ServerError::invalid_argument("invalid indexed limits"));
            }
            cfg.upload_limits.max_total_bytes = cfg
                .upload_limits
                .max_total_bytes
                .min(indexed.max_pack_bytes);
        }
        if let Some(policy) = &cfg.ref_policy {
            policy.validate_for_indexed(cfg.indexed.is_some())?;
        }
        #[cfg(feature = "http-objects")]
        if let Some(http) = &cfg.http_objects {
            let Some(indexed) = &cfg.indexed else {
                return Err(ServerError::invalid_argument(
                    "HTTP object serving requires indexed mode",
                ));
            };
            http.validate(indexed.extract_min_bytes)?;
            if http.admit_reads && hooks.admission().is_default() {
                return Err(ServerError::invalid_argument(
                    "paid HTTP reads require a real Admission hook",
                ));
            }
        }
        cfg.validate_server_info_limits()?;
        let mut credential_names = std::collections::BTreeSet::new();
        if cfg.admission_credential_headers.iter().any(|name| {
            !admission::valid_extra_name(name)
                || ["payment-authorization", "payment-signature"]
                    .contains(&name.to_ascii_lowercase().as_str())
                || !credential_names.insert(name.to_ascii_lowercase())
        }) {
            return Err(ServerError::invalid_argument(
                "invalid admission credential header name",
            ));
        }
        // Defaults (Payment-Authorization, PAYMENT-SIGNATURE, Authorization)
        // plus extras may never exceed the eight-header bound.
        if cfg.admission_credential_headers.len() + 3 > admission::MAX_CREDENTIAL_HEADERS {
            return Err(ServerError::invalid_argument(
                "too many admission credential headers",
            ));
        }
        cfg.redactor.add_names(&cfg.admission_credential_headers);

        if cfg.max_parts > B::MAX_PARTS {
            return Err(ServerError::invalid_argument(
                "max_parts exceeds storage backend capacity",
            ));
        }

        validate_upload_ticket_config(&cfg, &hooks)?;
        if cfg.ticket_ttl_ms == 0
            || cfg.ticket_ttl_ms >= 604_800_000
            || cfg.ticket_caps.per_ref == 0
            || cfg.ticket_caps.per_signer == 0
        {
            return Err(ServerError::invalid_argument(
                "invalid upload ticket lifetime or caps",
            ));
        }
        let policy_refusal = match (&cfg.addressing, cfg.write_policy) {
            (Addressing::Multi(_), WritePolicy::Open) => {
                Some("write_policy open is single-repository only (SPEC-TRANSPORT-CONNECT §7.5)")
            }
            // Owner on Single is the ssh root mode's policy: it needs a
            // self-certifying namespace (§7.4) to check principals against.
            // A bare `root` Single has none and stays refused.
            (Addressing::Single { repo }, WritePolicy::Owner)
                if Namespace::parse(repo.namespace.as_str()).is_err() =>
            {
                Some("write_policy owner needs multi-repository addressing")
            }
            (Addressing::Multi(multi), _)
                if matches!(
                    multi.namespace_policy,
                    NamespacePolicy::Any {
                        unsafe_without_admission: false
                    }
                ) && hooks.admission().is_default() =>
            {
                Some(
                    "namespace_policy any needs a non-default admission step, or the explicit unsafe override (D27)",
                )
            }
            _ => None,
        };
        if let Some(message) = policy_refusal {
            return Err(ServerError::invalid_argument(message));
        }
        if let Some(grants) = &cfg.grants {
            let AuthMode::AuthV2(auth) = &cfg.auth else {
                return Err(ServerError::invalid_argument(
                    "write grants require auth v2",
                ));
            };
            if !matches!(cfg.addressing, Addressing::Multi(_))
                || cfg.write_policy != WritePolicy::Owner
            {
                return Err(ServerError::invalid_argument(
                    "write grants require Multi addressing and owner write policy",
                ));
            }
            if grants.audience() != auth.audience() {
                return Err(ServerError::invalid_argument(
                    "write grant audience must match auth v2 audience",
                ));
            }
        }
        if let Some(tokens) = &cfg.url_tokens {
            if !matches!(cfg.auth, AuthMode::AuthV2(_)) {
                return Err(ServerError::invalid_argument("URL tokens require auth v2"));
            }
            // §9.4: the URL-token key is dedicated; a shared ticket secret
            // would let ticket MACs stand in for URL-token signatures.
            if let Some(tickets) = &cfg.ticket_keys
                && tokens
                    .keys()
                    .public_keys()
                    .any(|public| tickets.contains_ed25519_public(&public))
            {
                return Err(ServerError::invalid_argument(
                    "the URL token key must differ from the upload ticket keys",
                ));
            }
        }
        if let Some(tokens) = &cfg.history_tokens {
            if !matches!(cfg.auth, AuthMode::AuthV2(_)) {
                return Err(ServerError::invalid_argument(
                    "history tokens require auth v2",
                ));
            }
            tokens.check_roles(&cfg).map_err(|_| {
                ServerError::invalid_argument("the history continuation key must be dedicated")
            })?;
            cfg.admin_keys.push(tokens.public_key());
        }
        if cfg.authorizer_role == AuthorizerRole::Authority && hooks.authorizer().is_open() {
            return Err(ServerError::invalid_argument(
                "an authority authorizer must be a real authority source",
            ));
        }
        let caps = meta.capabilities();
        let full = caps.atomic_multi_key && caps.key_classes == KeyClasses::All;
        let refused = if matches!(cfg.auth, AuthMode::AuthV2(_)) && !full {
            "auth v2 needs every key class and atomic multi-key batches"
        } else if (cfg.sharding == Sharding::D34 || matches!(cfg.addressing, Addressing::Multi(_)))
            && !full
        {
            "sharded or multi-repository routing needs every key class and atomic multi-key batches"
        } else if !caps.atomic_multi_key && caps.implicit_layout_version.is_none() {
            "a store without atomic batches must report its layout version"
        } else if caps
            .implicit_layout_version
            .is_some_and(|v| v != keys::LAYOUT_VERSION)
        {
            "the store's layout version is not this server's"
        } else if cfg.lease_margin_ms == 0
            || cfg.epoch_lease_ms <= cfg.lease_margin_ms.saturating_add(cfg.min_lease_budget_ms)
        {
            "epoch lease must exceed its positive margin plus minimum budget"
        } else if cfg.list_page_limit == 0 || cfg.max_apply_window.is_zero() {
            "list page limit and apply window must be positive"
        } else {
            ""
        };
        if !refused.is_empty() {
            return Err(ServerError::invalid_argument(refused));
        }
        let shards: Arc<dyn ShardMap> = match cfg.sharding {
            Sharding::Single => Arc::new(SinglePartition),
            Sharding::D34 => Arc::new(D34Shards),
        };
        #[cfg(feature = "http-objects")]
        let http_seams = cfg.http_objects.as_ref().map(|http| {
            let mut seams = crate::http_objects::HttpSeams::new(http);
            if let Some(tokens) = &cfg.url_tokens {
                seams.tokens = Arc::new(tokens.clone());
            }
            seams
        });
        Ok(Self {
            publication_policy: None,
            #[cfg(feature = "remote-hooks")]
            inspectors: Vec::new(),
            #[cfg(feature = "remote-hooks")]
            inspect_limit: inspection::MAX_OBJECTS,
            blobs,
            meta,
            hooks,
            shards,
            cfg,
            clock,
            metrics,
            #[cfg(feature = "__test-faults")]
            faults: None,
            #[cfg(feature = "__test-faults")]
            test_timer_gate: None,
            gate: None,
            pending_hold: None,
            #[cfg(feature = "http-objects")]
            http_seams,
        })
    }

    /// Total launch inspected-set cap, absent when inspection is disabled.
    #[must_use]
    pub fn inspection_max_objects(&self) -> Option<u32> {
        #[cfg(feature = "remote-hooks")]
        if !self.inspectors.is_empty() {
            return u32::try_from(self.inspect_limit).ok();
        }
        None
    }

    /// Configure the launch's synchronous, fail-closed inspectors.
    ///
    /// # Errors
    /// Invalid launch settings or a deployment without indexed, ticketed,
    /// restricted writes and atomic metadata.
    #[cfg(feature = "remote-hooks")]
    pub fn with_inspectors(
        mut self,
        inspectors: Vec<Arc<dyn inspection::ContentInspector>>,
        batch_max: usize,
    ) -> Result<Self, ServerError> {
        if inspectors.is_empty() {
            return Ok(self);
        }
        let mut names = std::collections::BTreeSet::new();
        if inspectors.len() > inspection::MAX_INSPECTORS
            || !(1..=inspection::MAX_OBJECTS).contains(&batch_max)
            || inspectors.iter().any(|i| {
                i.id().is_empty()
                    || !names.insert(i.id())
                    || i.phase() != inspection::InspectorPhase::Sync
                    || i.on_unavailable() != inspection::OnUnavailable::FailClosed
            })
        {
            return Err(ServerError::invalid_argument(
                "invalid launch inspection configuration",
            ));
        }
        if self.cfg.indexed.is_none()
            || self.cfg.write_policy == WritePolicy::Open
            || self.cfg.ticket_keys.is_none()
            || self.cfg.begin_upload_threshold_bytes != 0
            || !self.meta.capabilities().atomic_multi_key
        {
            return Err(ServerError::invalid_argument(
                "inspection requires indexed mode, restricted writes and ticketed uploads with threshold zero",
            ));
        }
        self.inspectors = inspectors;
        self.inspect_limit = batch_max;
        Ok(self)
    }

    /// Install test fault hooks (feature `__test-faults` only).
    #[cfg(feature = "__test-faults")]
    #[must_use]
    pub fn with_faults(mut self, hooks: impl FaultHooks + 'static) -> Self {
        self.faults = Some(Arc::new(hooks));
        self
    }

    /// Exclude an adapter's autonomous timer tick while a test directive drains.
    /// The adapter must use this same gate around its own ticks.
    #[cfg(feature = "__test-faults")]
    #[must_use]
    pub fn with_test_timer_gate(mut self, gate: Arc<tokio::sync::Mutex<()>>) -> Self {
        self.test_timer_gate = Some(gate);
        self
    }

    #[cfg(feature = "__test-faults")]
    async fn fault(
        &self,
        point: FaultPoint,
        op: &Operation,
        a: &Authenticated,
    ) -> Result<(), ServerError> {
        match &self.faults {
            Some(hooks) => hooks.at_boxed(point, op, a.test_directives()).await,
            None => Ok(()),
        }
    }

    /// Run the writes to one partition one at a time in this process: each
    /// write's read-plan-apply loop waits for the partition's gate, as a
    /// Durable Object's input gate serializes them on Workers. For a
    /// single-process server over a single-writer store (native `SQLite`,
    /// which commits one batch at a time anyway): concurrent writes that
    /// share a key, such as one signer's quota window, then never exhaust
    /// the re-plan bound and fail `aborted`. D34 lease-grant batches also
    /// take this gate after admission. Reads are not gated. Several
    /// processes on one store still race, through the optimistic loop.
    #[must_use]
    pub fn with_write_gate(mut self) -> Self {
        self.gate = Some(Arc::new(gate::WriteGate::new()));
        self
    }

    /// A second pipeline over the same stores, hooks, shard map, clock,
    /// metrics, test fault hooks and write gate, authenticating with
    /// `auth`: how one server hosts bindings with different identity
    /// sources on one root (an enc listener's `TransportIdentity` beside
    /// an HTTP listener's bearer token or auth v2) while its writes to a
    /// partition still pass one gate. Every other setting is `self`'s.
    ///
    /// # Errors
    /// As [`Self::new`] for `auth` over these stores.
    pub fn with_auth(&self, auth: AuthMode) -> Result<Self, ServerError>
    where
        B: Clone,
        N: Clone,
        H: Clone,
    {
        let mut cfg = self.cfg.clone();
        cfg.auth = auth;
        // Sibling enc/ssh pipelines do not mint object URL tokens.
        cfg.url_tokens = None;
        cfg.history_tokens = None;
        // Grants need auth v2 (`Self::new` refuses them otherwise), and a
        // transport-identity write has no header-grant path: `GrantConfig::verify`
        // needs the signed operation. WP-2.12 (registered grants over ssh/enc)
        // replaces this with a sibling exception in `Self::new`.
        if !matches!(cfg.auth, AuthMode::AuthV2(_)) {
            cfg.grants = None;
        }
        let mut sibling = Self::new(
            self.blobs.clone(),
            self.meta.clone(),
            self.hooks.clone(),
            cfg,
            Arc::clone(&self.clock),
            Arc::clone(&self.metrics),
        )?;
        sibling.shards = Arc::clone(&self.shards);
        sibling.gate.clone_from(&self.gate);
        sibling.pending_hold.clone_from(&self.pending_hold);
        #[cfg(feature = "remote-hooks")]
        {
            sibling.inspectors.clone_from(&self.inspectors);
            sibling.inspect_limit = self.inspect_limit;
        }
        #[cfg(feature = "__test-faults")]
        {
            sibling.faults.clone_from(&self.faults);
            sibling.test_timer_gate.clone_from(&self.test_timer_gate);
        }
        #[cfg(feature = "http-objects")]
        sibling.http_seams.clone_from(&self.http_seams);
        Ok(sibling)
    }

    /// Stages 0a and 1: verify credentials and map the identity. Pure and
    /// synchronous; writes no state. The result is bound to
    /// `meta.procedure`. Under `__test-faults` it also reads the request's
    /// test directives: the clock skew shifts business time, including the
    /// auth v2 validity window, for this request only.
    ///
    /// # Errors
    /// `unauthenticated` for missing or invalid credentials;
    /// `invalid_argument` for a malformed test directive. A rejection is
    /// recorded like any failed request (procedure, code, latency), with
    /// principal `none`: no entry point runs after it to record it.
    pub fn authenticate(&self, meta: &RequestMeta<'_>) -> Result<Authenticated, ServerError> {
        tracing::debug!(stage = "authenticate", procedure = method(meta.procedure));
        let result = self.authenticate_inner(meta);
        if let Err(err) = &result {
            self.outcome_for(meta.procedure, "none", "-")
                .record(Err(err));
        }
        result
    }

    fn authenticate_inner(&self, meta: &RequestMeta<'_>) -> Result<Authenticated, ServerError> {
        if self.cfg.namespace_mode == crate::namespace::NamespaceMode::Authority
            && (meta.header)("x-write-grant").is_some()
        {
            return Err(crate::namespace::owner_statements_refused());
        }
        let signed = auth::signed_request(&self.cfg.auth, meta)?;
        // SPEC-WRITE-GRANTS §4.2: a grant header without auth v2 fails on
        // any procedure of every deployment.
        if !signed && (meta.header)("x-write-grant").is_some() {
            return Err(ServerError::unauthenticated(
                "write grant requires auth v2 authorization",
            ));
        }
        let repo = self.cfg.addressing.resolve_with_mode(
            (meta.header)("x-repository").as_deref(),
            signed,
            self.cfg.namespace_mode,
        )?;
        let expected_repository = match (&self.cfg.addressing, &self.cfg.auth) {
            (Addressing::Single { .. }, AuthMode::AuthV2(cfg)) => cfg.repository(),
            _ => &repo.identity,
        }
        .to_owned();
        #[cfg(feature = "__test-faults")]
        let directives = TestDirectives::from_headers(meta.header)?;
        #[cfg(feature = "__test-faults")]
        let skew = directives.clock_skew_ms;
        #[cfg(not(feature = "__test-faults"))]
        let skew = 0;
        let now = self.clock.now_ms().saturating_add(skew);
        let mut a = auth::authenticate(
            &self.cfg.auth,
            meta,
            now,
            repo,
            &expected_repository,
            signed,
        )?;
        if a.principal
            .ed25519()
            .is_some_and(|key| self.cfg.admin_keys.contains(key))
        {
            return Err(ServerError::unauthenticated(
                "admin key cannot authenticate client calls",
            ));
        }
        if a.principal.ed25519().is_some_and(|key| {
            self.cfg
                .scanner_retrieval
                .as_ref()
                .is_some_and(|config| config.scanner_keys().any(|public| &public == key))
        }) {
            return Err(ServerError::unauthenticated(
                "scanner key cannot authenticate client calls",
            ));
        }
        // Capture stable credential scope for signed reads as well as writes.
        // Reads do not run admission; visibility requests keep their existing
        // credential exclusion on their separate admission path (§9.1).
        if matches!(self.cfg.auth, AuthMode::AuthV2(_))
            && a.auth.is_some()
            && meta.procedure != Procedure::SetRepoVisibility
        {
            a.credential_capture =
                admission::capture_credentials(meta, &self.cfg.admission_credential_headers);
        }
        // Header adapters supply UTF-8 Strings; undecodable bytes are absent.
        a.ref_hint =
            (meta.header)("x-mkit-ref").filter(|name| name.len() <= refs::MAX_REF_NAME_BYTES);
        a.business_skew_ms = skew;
        #[cfg(feature = "__test-faults")]
        a.set_test_directives(directives);
        Ok(a)
    }

    /// Every ref of the repository under `prefix` at a path-component
    /// boundary, with the prefix and its `/` stripped (SPEC-REFS §4, see
    /// [`refs::list_scan_prefix`]), read page by page.
    ///
    /// # Errors
    /// `not_found` for a nonexistent Multi repository;
    /// `invalid_argument` for an invalid prefix or one over
    /// [`refs::MAX_REF_NAME_BYTES`]; the authorizer's error; `unavailable`
    /// for a bucket scan failure.
    pub async fn list_refs(
        &self,
        a: &Authenticated,
        prefix: &str,
    ) -> Result<Vec<RefEntry>, ServerError> {
        let mut out = Vec::new();
        let mut token = None;
        loop {
            let page = self
                .list_refs_page(a, prefix, Some(self.cfg.list_page_limit), token.as_deref())
                .await?;
            out.extend(page.refs);
            match page.next {
                Some(next) => token = Some(next),
                None => return Ok(out),
            }
        }
    }

    /// One bounded `ListRefs` page. The token is opaque core bytes; the
    /// Connect binding encodes it as unpadded base64url.
    #[allow(clippy::too_many_lines)] // One authorized listing with shared token and response bounds.
    pub(crate) async fn list_refs_page(
        &self,
        a: &Authenticated,
        prefix: &str,
        page_size: Option<u32>,
        token: Option<&[u8]>,
    ) -> Result<list::ListPage, ServerError> {
        let kind = OpKind::ListRefs {
            prefix: prefix.to_owned(),
        };
        self.observe(a, async {
            if prefix.trim_end_matches('/').len() > refs::MAX_REF_NAME_BYTES {
                return Err(ServerError::invalid_argument(refs::REF_NAME_TOO_LONG));
            }
            if !refs::validate_ref_prefix(prefix) {
                return Err(ServerError::invalid_argument(
                    "prefix is invalid (SPEC-REFS §3)",
                ));
            }
            let op = self.identify(a, kind)?;
            let authorized = self.authorize_read(&op).await?;
            let scan = refs::list_scan_prefix(prefix);
            let last = token
                .map(|bytes| {
                    list::decode_token(&op.repo, &scan, bytes)
                        .ok_or_else(|| ServerError::invalid_argument("invalid page token"))
                })
                .transpose()?;
            #[cfg(feature = "__test-faults")]
            {
                if a.test_directives().lease_recovered {
                    self.mark_lease_table_recovered(&op.repo.namespace).await?;
                }
                if let Some(epoch) = a.test_directives().bump_epoch {
                    self.test_bump_epoch(&op.repo.namespace, epoch).await?;
                }
            }
            #[cfg(feature = "__test-faults")]
            faults::run_timers(
                a.test_directives(),
                &self.meta,
                &self.blobs,
                self.shards.as_ref(),
                &op.repo,
                self.clock.as_ref(),
                ms(self.clock.now_ms().saturating_add(a.business_skew_ms)),
                self.test_timer_gate.as_deref(),
            )
            .await?;
            let requested = page_size.unwrap_or(0);
            let limit = if requested == 0 {
                self.cfg.max_list_refs_page_size
            } else {
                requested.min(self.cfg.max_list_refs_page_size)
            };
            let partitions = self.shards.ref_index_partitions(&op.repo);
            let view = crate::store::view::ViewStore {
                store: &self.meta,
                repo: &op.repo,
                writer: authorized.facts.caller_view == CallerView::Writer,
                policy: self.publication_policy.as_deref(),
            };
            let preparation = async {
                if matches!(self.cfg.addressing, Addressing::Multi(_)) {
                    if matches!(a.principal, Principal::Anonymous) {
                        self.meta.prepare_anonymous_repo_read(&op.repo).await;
                    } else if op.auth.is_some() {
                        self.meta.prepare_repo_read(&op.repo).await;
                    }
                }
            };
            let scan_page = async {
                if partitions.len() == 1 {
                    let bucket = list::RefBucket {
                        store: &view,
                        partition: &partitions[0],
                    };
                    list::page_in_waves(
                        &view,
                        &[bucket],
                        &op.repo,
                        &scan,
                        last.as_deref(),
                        limit,
                        list::MAX_RESPONSE_BYTES,
                    )
                    .await
                } else {
                    let buckets = partitions
                        .iter()
                        .map(|partition| list::IndexBucket {
                            store: &view,
                            partition,
                        })
                        .collect::<Vec<_>>();
                    list::page_in_waves(
                        &view,
                        &buckets,
                        &op.repo,
                        &scan,
                        last.as_deref(),
                        limit,
                        list::MAX_RESPONSE_BYTES,
                    )
                    .await
                }
            };
            // Authorization and token validation precede activation. Listing
            // scans carry snapshot semantics; response assembly follows both.
            let (result, ()) = futures::future::join(scan_page, preparation).await;
            let mut page = result.map_err(|err| {
                tracing::warn!(detail = %err, "ref listing scan failed");
                ServerError::unavailable("ref listing unavailable")
            })?;
            for entry in &mut page.refs {
                entry.name = strip_listed_prefix(&entry.name, prefix)
                    .ok_or_else(|| ServerError::unavailable("ref listing unavailable"))?
                    .to_owned();
            }
            Ok(page)
        })
        .await
    }

    /// Install the inspection preparation and immediate hold gate (post-launch WP-5.5c).
    /// Inspection requires indexed mode and an owner/authority write policy.
    pub fn with_publication_policy(
        mut self,
        policy: Arc<dyn clearance::PublicationPolicy>,
    ) -> Result<Self, ServerError> {
        if self.cfg.indexed.is_none() || self.cfg.write_policy == WritePolicy::Open {
            return Err(ServerError::invalid_argument(
                "inspection requires indexed mode and restricted writes",
            ));
        }
        self.publication_policy = Some(policy);
        Ok(self)
    }

    /// One ref's id, if it exists.
    ///
    /// # Errors
    /// `not_found` for a nonexistent Multi repository;
    /// `invalid_argument` for an invalid name; the authorizer's error;
    /// `internal` for a storage failure.
    pub async fn read_ref(
        &self,
        a: &Authenticated,
        name: &str,
    ) -> Result<Option<Hash>, ServerError> {
        let kind = OpKind::ReadRef {
            name: name.to_owned(),
        };
        self.observe(a, async {
            check_ref_name(name)?;
            let op = self.identify(a, kind)?;
            let authorized = self.authorize_read(&op).await?;
            let p = self.shards.ref_shard(&op.repo, name);
            let view = crate::store::view::ViewStore {
                store: &self.meta,
                repo: &op.repo,
                writer: authorized.facts.caller_view == CallerView::Writer,
                policy: self.publication_policy.as_deref(),
            };
            read::read_ref(&view, &p, &op.repo.name, name)
                .await
                .map_err(meta_error)
        })
        .await
    }

    /// Compare-and-swap one ref. A conflict is a result, not an error.
    ///
    /// # Errors
    /// See the stage functions; a stored rejection comes back as its error.
    pub async fn update_ref(
        &self,
        a: &Authenticated,
        upd: RefUpdate,
    ) -> Result<UpdateRefResult, ServerError> {
        self.update_ref_with_meta(a, upd)
            .await
            .map(|(result, _)| result)
    }

    /// Compare-and-swap a ref and return success-only admission headers.
    pub async fn update_ref_with_meta(
        &self,
        a: &Authenticated,
        upd: RefUpdate,
    ) -> Result<(UpdateRefResult, ResponseMeta), ServerError> {
        self.observe(a, async {
            check_ref_name(&upd.name)?;
            if upd.new.is_none()
                && !matches!(upd.condition, mkit_core::refs::RefWriteCondition::Match(_))
            {
                return Err(ServerError::invalid_argument(
                    "delete requires MATCH and an empty new_id",
                ));
            }
            match self.write(a, OpKind::UpdateRef(upd)).await? {
                (StoredResult::UpdateRef(result), meta) => Ok((result, meta)),
                (other, _) => Err(stored_mismatch(&other)),
            }
        })
        .await
    }

    /// Advance a branch head and its packmap together: one batch on an
    /// atomic store, else packmap then head (`Transport::advance_refs`'s
    /// default order).
    ///
    /// # Errors
    /// See the stage functions; a stored rejection comes back as its error.
    pub async fn advance_refs(
        &self,
        a: &Authenticated,
        head: RefUpdate,
        packmap: RefUpdate,
    ) -> Result<AdvanceOutcome, ServerError> {
        self.advance_refs_with_meta(a, head, packmap)
            .await
            .map(|(result, _)| result)
    }

    /// Advance refs and return success-only admission headers.
    pub async fn advance_refs_with_meta(
        &self,
        a: &Authenticated,
        head: RefUpdate,
        packmap: RefUpdate,
    ) -> Result<(AdvanceOutcome, ResponseMeta), ServerError> {
        self.advance_refs_with_tickets_with_meta(a, head, packmap, Vec::new())
            .await
    }

    /// Advance both refs while consuming the named upload tickets.
    ///
    /// # Errors
    /// Invalid ticket bindings, incomplete uploads, authorization or storage errors.
    pub async fn advance_refs_with_tickets(
        &self,
        a: &Authenticated,
        head: RefUpdate,
        packmap: RefUpdate,
        tickets: Vec<Hash>,
    ) -> Result<AdvanceOutcome, ServerError> {
        self.advance_refs_with_tickets_with_meta(a, head, packmap, tickets)
            .await
            .map(|(result, _)| result)
    }

    /// Advance refs with tickets and return success-only admission headers.
    pub async fn advance_refs_with_tickets_with_meta(
        &self,
        a: &Authenticated,
        head: RefUpdate,
        packmap: RefUpdate,
        tickets: Vec<Hash>,
    ) -> Result<(AdvanceOutcome, ResponseMeta), ServerError> {
        self.observe(a, async {
            check_ref_name(&head.name)?;
            check_ref_name(&packmap.name)?;
            if head.new.is_none() != packmap.new.is_none()
                || (head.new.is_none()
                    && (!matches!(head.condition, mkit_core::refs::RefWriteCondition::Match(_))
                        || !matches!(
                            packmap.condition,
                            mkit_core::refs::RefWriteCondition::Match(_)
                        )))
            {
                return Err(ServerError::invalid_argument(
                    "delete requires MATCH and an empty new_id",
                ));
            }
            if head.new.is_none() && !tickets.is_empty() {
                return Err(ServerError::invalid_argument("delete consumes no tickets"));
            }
            if tickets.len() > crate::store::outbox::MAX_TICKETS_PER_ADVANCE {
                return Err(ServerError::invalid_argument(
                    "too many tickets in one advance",
                ));
            }
            for ticket in &tickets {
                crate::telemetry::verification_progress(
                    self.metrics.as_ref(),
                    "advance_received",
                    ms(self.clock.now_ms()),
                    Some(ticket),
                    None,
                );
            }
            let mut distinct = std::collections::BTreeSet::new();
            if tickets.iter().any(|id| !distinct.insert(id)) {
                return Err(ServerError::invalid_argument("duplicate ticket id"));
            }
            // A ref policy or indexed mode checks the head only (and its
            // packmap through it), so the pair must be a real pair.
            if !tickets.is_empty()
                || self.cfg.sharding == Sharding::D34
                || self.cfg.ref_policy.is_some()
                || self.cfg.indexed.is_some()
            {
                let head_branch = head.name.strip_prefix("refs/heads/");
                let packmap_branch = packmap
                    .name
                    .strip_prefix(mkit_core::refs::PACKMAP_REF_PREFIX);
                if head_branch.is_none() || head_branch != packmap_branch {
                    if a.write_grant.is_some()
                        && self.cfg.grants.is_some()
                        && matches!(self.cfg.addressing, Addressing::Multi(_))
                    {
                        return Err(ServerError::permission_denied(
                            "write grant rejected: ref scope",
                        ));
                    }
                    return Err(ServerError::invalid_argument(if tickets.is_empty() {
                        "AdvanceRefs pairs refs/heads/<x> with refs/mkit/packmap/<x> on this server"
                    } else {
                        "ticketed advance requires a branch head and its packmap"
                    }));
                }
            }
            match self
                .write(
                    a,
                    OpKind::AdvanceRefs {
                        head,
                        packmap,
                        tickets,
                    },
                )
                .await?
            {
                (StoredResult::AdvanceRefs(outcome), meta) => Ok((outcome, meta)),
                (other, _) => Err(stored_mismatch(&other)),
            }
        })
        .await
    }

    /// Whether the pack is present in a Single deployment's blob store.
    /// Multi deployments require repository membership before serving packs.
    ///
    /// # Errors
    /// `not_found` for a nonexistent Multi repository; the authorizer's
    /// error; `internal` for a storage failure.
    pub async fn pack_exists(&self, a: &Authenticated, key: PackKey) -> Result<bool, ServerError> {
        self.observe(a, async {
            let op = self.identify(a, OpKind::PackExists { key })?;
            let authorized = self.authorize_read(&op).await?;
            let membership = self.pack_is_member(a, &key, authorized.facts.caller_view);
            let member = if matches!(op.principal, Principal::Anonymous)
                && matches!(self.cfg.addressing, Addressing::Multi(_))
            {
                let (member, ()) = futures::future::join(
                    membership,
                    Box::pin(self.meta.prepare_anonymous_repo_read(&op.repo)),
                )
                .await;
                member
            } else {
                membership.await
            };
            if !member? {
                return Ok(false);
            }
            let head = self.blobs.head(&key.into()).await;
            Ok(head
                .map_err(|e| store_error(StorageOp::BlobHead, e))?
                .is_some())
        })
        .await
    }

    /// `IssueObjectUrl` (SPEC-WRITE-GRANTS §9.4): mint a token binding the
    /// deployment's audience, the request's repository identity and
    /// `target` at the stored grant epoch. The target is never resolved —
    /// serving decides what it names, so minting reveals nothing about
    /// the repository's contents. The token is a credential: it is never
    /// logged.
    ///
    /// # Errors
    /// `unimplemented` when no URL-token key is configured, before any
    /// repository access; `unauthenticated` for an unsigned request
    /// (stage 0 already rejects it under auth v2); the read errors of
    /// `Self::authorize_read`, including the uniform `not_found` on a
    /// private repository.
    pub async fn issue_object_url(
        &self,
        a: &Authenticated,
        target: UrlTarget,
        ttl_seconds: u32,
    ) -> Result<MintedToken, ServerError> {
        self.observe(a, async {
            if self.cfg.url_tokens.is_none() {
                return Err(ServerError::unimplemented("URL tokens not configured"));
            }
            let op = self.identify(
                a,
                OpKind::IssueObjectUrl {
                    target: target.clone(),
                    ttl_seconds,
                },
            )?;
            self.issue_url(
                &op,
                &a.repo().identity,
                &target,
                ttl_seconds,
                a.business_now_ms,
            )
            .await
        })
        .await
    }

    // Shared below the wire envelope boundary: embedders transfer only verified
    // reader authority, while the RPC still requires its own signed envelope.
    async fn issue_url(
        &self,
        op: &Operation,
        repository: &str,
        target: &UrlTarget,
        ttl_seconds: u32,
        now_ms: i64,
    ) -> Result<MintedToken, ServerError> {
        self.issue_url_with_meta(
            op,
            repository,
            target,
            ttl_seconds,
            now_ms,
            &self.meta,
            None,
        )
        .await
    }

    #[allow(clippy::too_many_arguments)] // The reader captures inherited caps without changing RPC mappings.
    async fn issue_url_with_meta<S: NamespaceStore>(
        &self,
        op: &Operation,
        repository: &str,
        target: &UrlTarget,
        ttl_seconds: u32,
        now_ms: i64,
        meta: &S,
        read_cap_message: Option<&'static str>,
    ) -> Result<MintedToken, ServerError> {
        let Some(tokens) = &self.cfg.url_tokens else {
            return Err(ServerError::unimplemented("URL tokens not configured"));
        };
        let read = self
            .authorize_read_with_meta(op, meta, read_cap_message)
            .await?;
        let epoch = match read.epoch {
            Some(epoch) => epoch,
            None => {
                self.stored_grant_epoch_with_meta(&op.repo.namespace, meta)
                    .await?
            }
        };
        let AuthMode::AuthV2(auth) = &self.cfg.auth else {
            return Err(internal("URL tokens without auth v2"));
        };
        tokens.mint(
            auth.audience(),
            repository,
            target,
            epoch,
            now_ms,
            ttl_seconds,
        )
    }

    /// `SetRepoVisibility` (SPEC-WRITE-GRANTS §9.1): the envelope mode is a
    /// signed, replay-protected write of the `rv` row; the statement mode
    /// verifies an unsigned owner-signed statement and keeps the newest
    /// `created`. Only deployments where `Self::visibility_applies`
    /// holds have visibility at all.
    ///
    /// # Errors
    /// `unauthenticated` for an unsigned envelope request, `invalid_argument`
    /// for a statement on a signed request, `failed_precondition` when the
    /// deployment has no repository visibility, `permission_denied` for a
    /// grant, a non-owner, an unserved namespace or a rejected statement.
    pub async fn set_repo_visibility(
        &self,
        a: &Authenticated,
        req: VisibilityRequest,
    ) -> Result<(), ServerError> {
        self.set_repo_visibility_with_meta(a, req).await.map(|_| ())
    }

    /// [`Self::set_repo_visibility`], also returning the success-only
    /// admission headers (empty on a replay or an already-applied statement).
    ///
    /// Both modes run stage 3 (admission) before any state change and record
    /// an outcome after the commit, exactly as other writes do; the hooks see
    /// `Procedure::SetRepoVisibility` with `declared_bytes = 0`.
    ///
    /// # Errors
    /// Those of [`Self::set_repo_visibility`], plus an admission refusal or
    /// challenge, and `unavailable` while the outcome backlog is full.
    pub async fn set_repo_visibility_with_meta(
        &self,
        a: &Authenticated,
        req: VisibilityRequest,
    ) -> Result<ResponseMeta, ServerError> {
        self.observe(a, async {
            if !self.visibility_applies() {
                return Err(ServerError::failed_precondition(
                    "repository visibility is not supported by this deployment",
                ));
            }
            if self.cfg.namespace_mode == crate::namespace::NamespaceMode::Authority
                && matches!(req, VisibilityRequest::Statement(_))
            {
                return Err(crate::namespace::owner_statements_refused());
            }
            match (&req, a.auth.is_some()) {
                (VisibilityRequest::Statement(_), true) => {
                    return Err(ServerError::invalid_argument(
                        "signed_statement is not allowed on a signed request",
                    ));
                }
                (VisibilityRequest::Envelope(_), false) => {
                    return Err(ServerError::unauthenticated(
                        "visibility requires auth v2 authorization",
                    ));
                }
                _ => {}
            }
            let repo = &a.repo().repo;
            let namespace = self.cfg.namespace_mode.namespace(repo.namespace.as_str())
                .map_err(|_| internal("invalid resolved Multi namespace"))?;
            if let Addressing::Multi(multi) = &self.cfg.addressing
                && let NamespacePolicy::Allowlist(allowed) = &multi.namespace_policy
                && !matches!(&namespace, crate::namespace::Namespace::SelfCertifying(ns) if allowed.contains(ns))
            {
                return Err(ServerError::permission_denied("namespace not served"));
            }
            let p = self.shards.coordinator(&repo.namespace);
            let _gate = match &self.gate {
                Some(gate) => Some(gate.enter(&p).await),
                None => None,
            };
            match req {
                VisibilityRequest::Envelope(visibility) => {
                    self.visibility_envelope(a, repo, &p, visibility).await
                }
                VisibilityRequest::Statement(statement) => {
                    self.visibility_statement(a, repo, &p, &statement).await
                }
            }
        })
        .await
    }

    /// Envelope mode: the stage-0 replay lookup, owner-or-hook
    /// authorization mirroring the write branch (never a grant), then the
    /// guarded `rv` write with its replay record.
    #[allow(clippy::too_many_lines)] // Replay, authorization and both guarded visibility retries share one lifecycle.
    async fn visibility_envelope(
        &self,
        a: &Authenticated,
        repo: &RepoId,
        p: &Partition,
        visibility: Visibility,
    ) -> Result<ResponseMeta, ServerError> {
        if a.write_grant.is_some() {
            return Err(ServerError::permission_denied(
                "a grant never authorizes SetRepoVisibility",
            ));
        }
        let op = self.identify(a, OpKind::SetRepoVisibility { visibility })?;
        let auth = a.auth.as_ref().ok_or_else(|| {
            ServerError::unauthenticated("visibility requires auth v2 authorization")
        })?;
        let replay_key = keys::replay(&auth.replay_scope);
        let rv_key = keys::repo_visibility(&repo.name);
        let rows = self
            .meta
            .get_many(
                p,
                &[
                    replay_key.clone(),
                    rv_key.clone(),
                    keys::authority_generation(),
                    keys::lease_recovery(),
                ],
            )
            .await
            .map_err(meta_error)?;
        let mut rows = rows.into_iter();
        let record = rows
            .next()
            .flatten()
            .map(|v| codec::decode_replay_record(&v))
            .transpose()
            .map_err(meta_error)?;
        let stored = rows.next().flatten();
        match classify(record.as_ref(), &auth.fingerprint) {
            ReplayDecision::New => {}
            ReplayDecision::Return(StoredResult::RepoVisibility) => {
                return Ok(ResponseMeta::default());
            }
            ReplayDecision::Return(other) => return Err(stored_mismatch(&other)),
            ReplayDecision::FingerprintMismatch => {
                return Err(ServerError::invalid_argument(
                    "nonce reused for a different operation",
                ));
            }
            ReplayDecision::Resume | ReplayDecision::RetryLater => {
                return Err(ServerError::aborted_retryable(
                    "operation already in flight; retry",
                ));
            }
        }
        Box::pin(self.ensure_authority_activation(&repo.namespace)).await?;
        let facts = self.authorize_visibility_envelope(&op).await?;
        let mut op = op;
        op.authz = facts.clone();
        let hides = visibility == Visibility::Private
            && !repo_is_private(
                stored
                    .as_ref()
                    .map(codec::decode_repo_visibility)
                    .transpose()
                    .map_err(meta_error)?
                    .as_ref(),
                self.cfg.default_repo_visibility,
            );
        let admitted = self.admit_visibility(a, &op, p, hides).await?;
        let committed = self
            .commit_visibility_envelope(
                (auth, repo, p),
                (visibility, &facts, &admitted),
                stored,
                (&replay_key, &rv_key),
            )
            .await;
        self.settle_visibility(p, admitted, committed).await
    }

    /// The guarded envelope commit: re-plan on contention until it lands.
    #[allow(clippy::too_many_lines)] // Both guarded visibility retries share one lifecycle.
    async fn commit_visibility_envelope(
        &self,
        (auth, repo, p): (&VerifiedAuth, &RepoId, &Partition),
        (visibility, facts, admitted): (Visibility, &AuthzFacts, &visibility_hooks::Admitted),
        mut stored: Option<Value>,
        (replay_key, rv_key): (&Key, &Key),
    ) -> Result<visibility_hooks::Landed, ServerError> {
        let mut replans = 0;
        loop {
            let (mut batch, prune) = self
                .plan_visibility(p, auth, repo, visibility, stored.as_ref(), admitted)
                .await?;
            let fence_rows = self
                .meta
                .get_many(p, &[keys::authority_generation(), keys::lease_recovery()])
                .await
                .map_err(meta_error)?;
            let [generation_value, mode_value] = fence_rows.as_slice() else {
                return Err(internal("visibility fence row count"));
            };
            let mode = mode_value
                .as_ref()
                .map(codec::decode_lease_recovery)
                .transpose()
                .map_err(meta_error)?;
            if facts.authority_generation.is_none()
                && (generation_value.is_some()
                    || mode.is_some_and(|m| m.authority_fence == Some(true)))
            {
                return Err(ServerError::unavailable(
                    "persisted authority fence requires enabled executor",
                ));
            }
            batch = batch.require(lease::observed_guard(
                keys::lease_recovery(),
                mode_value.as_ref(),
            ));
            if let Some(generation) = facts.authority_generation {
                let current = generation_value
                    .as_ref()
                    .map(codec::decode_u64)
                    .transpose()
                    .map_err(meta_error)?
                    .unwrap_or(0);
                if current != generation {
                    return Err(crate::authority::moved());
                }
                batch = batch.require(lease::observed_guard(
                    keys::authority_generation(),
                    generation_value.as_ref(),
                ));
            }
            match self.meta.apply(p, batch).await {
                Ok(BatchOutcome::Committed) => {
                    self.invalidate_local_cache(repo).await;
                    return Ok(visibility_hooks::Landed::Committed);
                }
                Ok(BatchOutcome::DeadlinePassed { .. }) => {
                    return Err(ServerError::unavailable("commit deadline passed; retry"));
                }
                Ok(BatchOutcome::PreconditionFailed { index, .. }) => {
                    if index == 1 {
                        // The replay guard failed: a request with this
                        // nonce landed first; answer it as stage 0 does.
                        let value = self.meta.get(p, replay_key).await.map_err(meta_error)?;
                        let record = value
                            .as_ref()
                            .map(codec::decode_replay_record)
                            .transpose()
                            .map_err(meta_error)?;
                        return match classify(record.as_ref(), &auth.fingerprint) {
                            ReplayDecision::Return(StoredResult::RepoVisibility) => {
                                Ok(visibility_hooks::Landed::Replayed)
                            }
                            ReplayDecision::Return(other) => Err(stored_mismatch(&other)),
                            ReplayDecision::FingerprintMismatch => {
                                Err(ServerError::invalid_argument(
                                    "nonce reused for a different operation",
                                ))
                            }
                            _ => Err(ServerError::aborted_retryable(
                                "operation already in flight; retry",
                            )),
                        };
                    }
                    replans += 1;
                    if replans > MAX_REPLAN {
                        return Err(ServerError::aborted_retryable("write contention; retry"));
                    }
                    self.require_pending_current(p, admitted).await?;
                    stored = self.meta.get(p, rv_key).await.map_err(meta_error)?;
                }
                Err(StoreError::Full) => {
                    return Err(self.partition_full(p, prune).await);
                }
                Err(e) => return Err(meta_error(e)),
            }
        }
    }

    /// Envelope-mode authorization: the owner, or (`authority` role) the
    /// hook, which is shown a reader until it decides. Hook errors are
    /// stripped of any admission shape.
    async fn authorize_visibility_envelope(
        &self,
        op: &Operation,
    ) -> Result<AuthzFacts, ServerError> {
        let owner = self.namespace_owner(&op.repo, &op.principal);
        if self.cfg.authorizer_role == AuthorizerRole::Check && !owner {
            return Err(ServerError::permission_denied(
                "SetRepoVisibility not permitted",
            ));
        }
        let mut authorized = op.clone();
        authorized.authz = AuthzFacts {
            authority_generation: None,
            grant: None,
            owner,
            // The hook decides whether a non-owner may write; until it
            // does the caller is only a reader.
            caller_view: if owner {
                CallerView::Writer
            } else {
                CallerView::Reader
            },
        };
        let returned = self
            .hooks
            .authorizer()
            .authorize(&authorized)
            .await
            .map_err(ServerError::strip_admission_shape)?;
        self.merge_authority_facts(&mut authorized.authz, &returned)?;
        Ok(authorized.authz)
    }

    /// One envelope attempt: deadline, replay `Absent`, the `rv` guard and
    /// its new row, the replay record and expiry index, then up to 32
    /// expired replay `(index, record)` deletes capped at `MAX_BATCH_OPS`.
    /// Returns the commit batch plus the delete-only batch a full
    /// partition can still apply.
    async fn plan_visibility(
        &self,
        p: &Partition,
        auth: &VerifiedAuth,
        repo: &RepoId,
        visibility: Visibility,
        stored: Option<&Value>,
        admitted: &visibility_hooks::Admitted,
    ) -> Result<(Batch, Option<Batch>), ServerError> {
        let now = ms(self.clock.now_ms());
        let window = u64::try_from(self.cfg.max_apply_window.as_millis()).unwrap_or(u64::MAX);
        let deadline = now
            .saturating_add(window)
            .min(ms(auth.expires_at_ms).saturating_add(MAX_CLOCK_LEAD_MS.unsigned_abs()))
            .min(admitted.apply_deadline_ms());
        let replay_key = keys::replay(&auth.replay_scope);
        let rv_key = keys::repo_visibility(&repo.name);
        let row = stored
            .map(codec::decode_repo_visibility)
            .transpose()
            .map_err(meta_error)?;
        let mut batch = Batch::new()
            .require(Precondition::NotAfter(deadline))
            .require(Precondition::Absent(replay_key.clone()))
            .require(match stored {
                Some(value) => Precondition::Equals(rv_key.clone(), value.clone()),
                None => Precondition::Absent(rv_key.clone()),
            })
            .put(
                rv_key.clone(),
                codec::encode_repo_visibility(&codec::RepoVisibilityV1 {
                    visibility: stored_visibility(visibility),
                    // An envelope write is newer than any statement made
                    // before it: an older unsubmitted statement must not
                    // undo it (§9.1).
                    last_created_ms: row.as_ref().map_or(0, |r| r.last_created_ms).max(now),
                    last_statement_id: row.and_then(|r| r.last_statement_id),
                    changed_ms: now,
                }),
            )
            .put(
                replay_key.clone(),
                codec::encode_replay_record(&ReplayRecord {
                    fingerprint: auth.fingerprint,
                    expires_at_ms: auth.expires_at_ms,
                    state: ReplayState::Committed(StoredResult::RepoVisibility),
                }),
            )
            .put(
                keys::replay_expiry(ms(auth.expires_at_ms), &auth.replay_scope),
                Value::default(),
            );
        self.plan_listing_visibility(p, repo, &mut batch).await?;
        let expired = read::expired_replay_keys(&self.meta, p, now, 32)
            .await
            .map_err(meta_error)?;
        let purge = self
            .plan_repository_purge(
                p,
                repo,
                crate::purge::Trigger::VisibilityChange,
                &mkit_core::hash::to_hex(&auth.replay_scope),
                now,
            )
            .await?;
        batch.preconditions.extend(purge.preconditions);
        batch.writes.extend(purge.writes);
        self.plan_visibility_settlement(p, &mut batch, admitted, now)
            .await?;
        visibility_hooks::check_batch_room(&batch, visibility_hooks::FENCE_GUARDS)?;
        let mut prune = Batch::new().require(Precondition::NotAfter(deadline));
        for (index, target) in &expired {
            if batch.preconditions.len() + batch.writes.len() + 2 + visibility_hooks::FENCE_GUARDS
                > MAX_BATCH_OPS
            {
                break;
            }
            batch = batch.delete(index.clone()).delete(target.clone());
            prune = prune.delete(index.clone()).delete(target.clone());
        }
        Ok((batch, (!prune.writes.is_empty()).then_some(prune)))
    }

    /// Statement mode: the owner-signed statement is its own
    /// authorization; only a strictly newer `created` replaces the stored
    /// one. There is no authorizer call and no replay record, but a change
    /// that would write runs admission first and records an outcome, like
    /// the envelope mode (an already-applied or stale statement allocates
    /// nothing).
    #[allow(clippy::too_many_lines)] // Verification, admission and the guarded retry share one lifecycle.
    async fn visibility_statement(
        &self,
        a: &Authenticated,
        repo: &RepoId,
        p: &Partition,
        statement: &str,
    ) -> Result<ResponseMeta, ServerError> {
        let rejected = |e: mkit_attest::grant::GrantError| {
            ServerError::permission_denied(format!("visibility statement rejected: {}", e.reason()))
        };
        if statement.len() > mkit_attest::grant::MAX_GRANT_HEADER_BYTES {
            return Err(ServerError::permission_denied(
                "visibility statement rejected: too long",
            ));
        }
        let grants = self.cfg.grants.as_ref().ok_or_else(|| {
            ServerError::permission_denied(
                "visibility statement rejected: no owner schemes configured",
            )
        })?;
        let identity = RepositoryIdentity::parse(&a.repo().identity)
            .map_err(|_| internal("invalid resolved repository identity"))?;
        let verified =
            verify_visibility_statement(grants.verifier(), statement, &identity, a.business_now_ms)
                .map_err(rejected)?;
        if let Some(namespace) = identity.namespace() {
            self.require_client_owner_key(namespace)?;
        }
        let created = u64::try_from(verified.statement().created_ms)
            .map_err(|_| rejected(mkit_attest::grant::GrantError::DecimalOutOfRange))?;
        let id = to_hex(verified.id());
        let visibility = verified.statement().visibility;
        let rv_key = keys::repo_visibility(&repo.name);
        let window = u64::try_from(self.cfg.max_apply_window.as_millis()).unwrap_or(u64::MAX);
        let mut admitted: Option<visibility_hooks::Admitted> = None;
        let landed = async {
            let mut replans = 0;
            loop {
                let stored = self.meta.get(p, &rv_key).await.map_err(meta_error)?;
                let row = stored
                    .as_ref()
                    .map(codec::decode_repo_visibility)
                    .transpose()
                    .map_err(meta_error)?;
                match &row {
                    // The stored statement is this one: already applied.
                    Some(r)
                        if r.last_created_ms == created
                            && r.last_statement_id.as_deref() == Some(id.as_str())
                            && r.visibility == stored_visibility(visibility) =>
                    {
                        return Ok(visibility_hooks::Landed::Replayed);
                    }
                    Some(r) if created <= r.last_created_ms => {
                        return Err(ServerError::permission_denied(
                            "visibility statement rejected: not newer than the stored statement",
                        ));
                    }
                    _ => {}
                }
                // Stage 3, once, for a change that will be written. The
                // statement's signer is the namespace owner.
                if admitted.is_none() {
                    let mut op = self.identify(a, OpKind::SetRepoVisibility { visibility })?;
                    op.authz = AuthzFacts {
                        owner: true,
                        caller_view: CallerView::Writer,
                        ..AuthzFacts::default()
                    };
                    let hides = visibility == Visibility::Private
                        && !repo_is_private(row.as_ref(), self.cfg.default_repo_visibility);
                    admitted = Some(self.admit_visibility(a, &op, p, hides).await?);
                }
                let Some(admission) = admitted.as_ref() else {
                    return Err(internal("visibility admission missing"));
                };
                let deadline = ms(self.clock.now_ms())
                    .saturating_add(window)
                    .min(admission.apply_deadline_ms());
                let rv_guard = match &stored {
                    Some(value) => Precondition::Equals(rv_key.clone(), value.clone()),
                    None => Precondition::Absent(rv_key.clone()),
                };
                let mut batch = Batch::new()
                    .require(Precondition::NotAfter(deadline))
                    .require(rv_guard)
                    .put(
                        rv_key.clone(),
                        codec::encode_repo_visibility(&codec::RepoVisibilityV1 {
                            visibility: stored_visibility(visibility),
                            last_created_ms: created,
                            last_statement_id: Some(id.clone()),
                            changed_ms: ms(self.clock.now_ms()),
                        }),
                    );
                self.plan_listing_visibility(p, repo, &mut batch).await?;
                let purge = self
                    .plan_repository_purge(
                        p,
                        repo,
                        crate::purge::Trigger::VisibilityChange,
                        &id,
                        ms(self.clock.now_ms()),
                    )
                    .await?;
                batch.preconditions.extend(purge.preconditions);
                batch.writes.extend(purge.writes);
                self.plan_visibility_settlement(p, &mut batch, admission, ms(self.clock.now_ms()))
                    .await?;
                match self.meta.apply(p, batch).await {
                    Ok(BatchOutcome::Committed) => {
                        self.invalidate_local_cache(repo).await;
                        return Ok(visibility_hooks::Landed::Committed);
                    }
                    Ok(BatchOutcome::DeadlinePassed { .. }) => {
                        return Err(ServerError::unavailable("commit deadline passed; retry"));
                    }
                    Ok(BatchOutcome::PreconditionFailed { .. }) => {
                        replans += 1;
                        if replans > MAX_REPLAN {
                            return Err(ServerError::aborted_retryable("write contention; retry"));
                        }
                        self.require_pending_current(p, admission).await?;
                    }
                    Err(StoreError::Full) => return Err(self.partition_full(p, None).await),
                    Err(e) => return Err(meta_error(e)),
                }
            }
        }
        .await;
        match admitted {
            Some(admitted) => self.settle_visibility(p, admitted, landed).await,
            None => landed.map(|_| ResponseMeta::default()),
        }
    }

    /// Stages 0–3 of an `UploadPack` whose header declared `pack_id` and
    /// `total_bytes` (`None` when absent): framing, the signed `pack:`
    /// commitment, the replay lookup, authorization, admission and, for a
    /// new signed operation, the reservation. Nothing is read from the
    /// stream before it returns.
    ///
    /// # Errors
    /// `failed_precondition` when the advertised threshold requires a ticket;
    /// the header's [`crate::upload::UploadError`]; `unauthenticated` when
    /// the header differs from the signed commitment; a stored or
    /// in-flight replay answer; a hook's error; the reservation's error.
    pub async fn open_upload(
        &self,
        a: &Authenticated,
        pack_id: Option<&[u8]>,
        total_bytes: Option<u64>,
    ) -> Result<UploadSession<'_, B, N, H>, ServerError> {
        UploadSession::begin(self, a, pack_id, total_bytes).await
    }

    /// Open a stateless ticketed `UploadPack` stream after checking the header,
    /// signed commitment and token, before reading any body bytes.
    ///
    /// # Errors
    /// Framing, authentication, binding and blob-store failures.
    pub async fn open_ticketed_upload(
        &self,
        a: &Authenticated,
        pack_id: Option<&[u8]>,
        total_bytes: Option<u64>,
        token: &[u8],
    ) -> Result<UploadSession<'_, B, N, H>, ServerError> {
        UploadSession::begin_ticketed(self, a, pack_id, total_bytes, token).await
    }

    /// A pack's bytes as chunks of at most `download_chunk_max` bytes.
    ///
    /// # Errors
    /// `not_found` for a missing repository or non-member pack, before any chunk; the authorizer's
    /// error; `internal` for a storage failure.
    ///
    /// The request is recorded `ok` when the `last` chunk is yielded, with
    /// its error at the first failure, and as `canceled` when the stream is
    /// dropped before either.
    pub async fn download(
        &self,
        a: &Authenticated,
        key: PackKey,
    ) -> Result<DownloadStream, ServerError> {
        let mut outcome = self.outcome(a);
        let opened = async {
            let op = self.identify(a, OpKind::DownloadPack { key })?;
            let authorized = self.authorize_read(&op).await?;
            let membership = self.pack_is_member(a, &key, authorized.facts.caller_view);
            let member = if matches!(op.principal, Principal::Anonymous)
                && matches!(self.cfg.addressing, Addressing::Multi(_))
            {
                let (member, ()) = futures::future::join(
                    membership,
                    Box::pin(self.meta.prepare_anonymous_repo_read(&op.repo)),
                )
                .await;
                member
            } else {
                membership.await
            };
            if !member? {
                return Err(ServerError::not_found("pack not found"));
            }
            let body = self.blobs.get(&key.into(), None).await;
            match body.map_err(|e| store_error(StorageOp::BlobGet, e))? {
                Some(body) => Ok(body),
                None => Err(ServerError::not_found("pack not found")),
            }
        }
        .instrument(outcome.span.clone())
        .await;
        match opened {
            Ok(body) => {
                let max = self.cfg.download_chunk_max;
                Ok(DownloadStream::new(body, max, Some(outcome)))
            }
            Err(err) => {
                outcome.record(Err(&err));
                Err(err)
            }
        }
    }

    /// Probe both stores.
    pub async fn health(&self) -> HealthStatus {
        HealthStatus {
            blobs: self.blobs.probe().await.is_ok(),
            meta: self.meta.probe().await.is_ok(),
        }
    }

    /// How this pipeline authenticates (the ssh session requires
    /// `TransportIdentity`; an HTTP adapter may pre-check a bearer token
    /// before it spends resources on the request).
    #[must_use]
    pub fn auth_mode(&self) -> &AuthMode {
        &self.cfg.auth
    }

    /// The upload caps `begin_upload` applies: a binding that validates
    /// framing itself uses the same ones.
    #[cfg(feature = "ssh")]
    pub(crate) fn upload_limits(&self) -> UploadLimits {
        self.cfg.upload_limits
    }

    /// The metadata store, for the ssh tests' state checks.
    #[cfg(all(test, feature = "ssh"))]
    pub(crate) fn meta_store(&self) -> &N {
        &self.meta
    }

    /// What this pipeline offers.
    pub fn capabilities(&self) -> PipelineCapabilities {
        PipelineCapabilities {
            leases: false,
            atomic_advance: self.meta.capabilities().atomic_multi_key,
        }
    }

    /// Add a response header to `err`, counting a dropped one in
    /// [`METRIC_HEADER_DROPPED`] (what [`ServerError::with_header`] cannot
    /// do without a metrics sink). The value is never logged.
    #[must_use]
    pub fn with_header(&self, err: ServerError, name: &str, value: &str) -> ServerError {
        match err.clone().try_with_header(name, value) {
            Ok(err) => err,
            Err(reason) => {
                let label = match reason {
                    InvalidHeader::Name => "name",
                    InvalidHeader::Reserved => "reserved",
                    InvalidHeader::Value => "value",
                };
                tracing::warn!(header = ?name, %reason, "dropped an error response header");
                self.metrics
                    .incr(METRIC_HEADER_DROPPED, &[("reason", label)], 1);
                err
            }
        }
    }

    /// The span, request metrics and outcome log around one entry point.
    async fn observe<T>(
        &self,
        a: &Authenticated,
        fut: impl Future<Output = Result<T, ServerError>>,
    ) -> Result<T, ServerError> {
        let mut outcome = self.outcome(a);
        let result = fut.instrument(outcome.span.clone()).await;
        outcome.record(result.as_ref().map(|_| ()));
        result
    }

    /// The span and recorder of one request.
    fn outcome(&self, a: &Authenticated) -> RequestOutcome {
        self.outcome_for(a.procedure(), a.principal.kind(), &a.repo().identity)
    }

    /// The span and recorder of one request to `procedure` as `principal`.
    fn outcome_for(
        &self,
        procedure: Procedure,
        principal: &'static str,
        repo: &str,
    ) -> RequestOutcome {
        let procedure = method(procedure);
        let span = tracing::info_span!("mkit.server.rpc", procedure, repo, principal);
        let (metrics, clock) = (self.metrics.clone(), self.clock.clone());
        RequestOutcome::new(span, procedure, metrics, clock, self.cfg.redactor.clone())
    }

    /// A signed or unsigned unary write, stage by stage. In steady state
    /// a signed write costs two backend calls: one `get_many` before any
    /// hook runs (the replay record and the snapshot) and one `apply`.
    fn write<'a>(
        &'a self,
        a: &'a Authenticated,
        kind: OpKind,
    ) -> crate::rt::BoxFuture<'a, Result<(StoredResult, ResponseMeta), ServerError>> {
        self.write_with(a, kind, None)
    }

    /// [`Self::write`], optionally consuming the session's pending packs
    /// as implicit tickets (WP-1.15): the B10 packmap check runs after
    /// authorization, custom admission covers the ref effects with zero
    /// bytes, and under Multi the plan adds membership and relay rows.
    fn write_with<'a>(
        &'a self,
        a: &'a Authenticated,
        kind: OpKind,
        implicit: Option<&'a [PendingPack]>,
    ) -> crate::rt::BoxFuture<'a, Result<(StoredResult, ResponseMeta), ServerError>> {
        if self.pending_hold.is_none() {
            Box::pin(async move {
                let mut heads = advance::TicketHeads::default();
                self.write_inner(a, kind, implicit, None, &mut heads).await
            })
        } else {
            Box::pin(self.write_with_pending_hold(a, kind, implicit))
        }
    }

    #[allow(clippy::too_many_lines)] // Stage order and multipart session cleanup share this entry point.
    async fn write_inner(
        &self,
        a: &Authenticated,
        kind: OpKind,
        implicit: Option<&[PendingPack]>,
        source: Option<(&str, Option<Hash>)>,
        heads: &mut advance::TicketHeads,
    ) -> Result<(StoredResult, ResponseMeta), ServerError> {
        let mut op = self.identify(a, kind)?;
        fault!(self, AfterAuthenticate, &op, a);
        let (kind, mut refs, p) = self.ref_writes(&op)?;
        let mut ahead = self.read_ahead(&op, &p, &refs, a.business_skew_ms).await?;
        if let Some(stored) = Self::replay_lookup(&op, ahead.as_ref())? {
            return Ok((stored, ResponseMeta::default()));
        }
        if let Some((source_ref, expected_tip)) = source {
            let captured = self
                .capture_published_source(&op, source_ref, expected_tip, &self.meta)
                .await?;
            refs[0].new = captured.pair.packmap;
            refs[1].new = captured.pair.head;
            if let OpKind::AdvanceRefs { head, packmap, .. } = &mut op.kind {
                head.new = captured.pair.head;
                packmap.new = captured.pair.packmap;
            }
            op.published_source = Some(captured);
        }
        let lease = if self.cfg.sharding == Sharding::D34 {
            let observed = self.observe_lease(&op, &p, ahead.as_ref(), None).await?;
            if let Some((window, total)) = observed.quota_seed()
                && let Some(snapshot) = ahead.as_mut()
            {
                snapshot.namespace_seed = Some((
                    window,
                    codec::encode_namespace_view(NamespaceView {
                        total,
                        pushed: crate::quota::NamespaceUsage::default(),
                        observed_at_ms: ms(self.clock.now_ms()),
                    }),
                ));
            }
            op.creation = observed.creation(&self.cfg.addressing);
            op.leased_epoch = Some(observed.epoch());
            Some(observed)
        } else {
            op.creation = self.creation_facts(&op, ahead.as_ref()).await?;
            None
        };
        if self.cfg.sharding == Sharding::Single {
            let key = keys::grant_epoch();
            if let Some(snapshot) = ahead.as_ref().filter(|snapshot| snapshot.contains(&key)) {
                op.observed_epoch = Some(
                    snapshot
                        .get(&key)
                        .map(codec::decode_u64)
                        .transpose()
                        .map_err(meta_error)?
                        .unwrap_or(0),
                );
            }
        }
        let (authz, fast_forward) = self.authorize(&op).await?;
        op.authz = authz;
        fault!(self, AfterAuthorize, &op, a);
        // §9.7: the signer rule needs no verified content, so it runs first.
        if let Err(error) = self.check_ref_signers(&op) {
            return self
                .store_policy_denial(&op, a, &p, ahead, error, (false, None))
                .await
                .map(|stored| (stored, ResponseMeta::default()));
        }
        let ticketed =
            matches!(&op.kind, OpKind::AdvanceRefs { tickets, .. } if !tickets.is_empty());
        let default_admission = self.hooks.admission().is_default();
        let defer_verification = ticketed
            && !default_admission
            && self.cfg.indexed.is_some_and(|indexed| {
                indexed.verification == crate::indexed::VerificationMode::Inline
            });
        let mut staged = crate::indexed::verify::StagedCommits::default();
        let mut ticket_ms = None;
        if ticketed {
            let snap = ahead
                .as_mut()
                .ok_or_else(|| internal("ticket advance requires atomic metadata"))?;
            if let Some(stored) = self.ticket_decision(&op, a, &p, snap, heads).await? {
                return Ok((stored, ResponseMeta::default()));
            }
            // Pending scheduled jobs remain admission-free polling answers.
            // Inline verification can write state, so custom admission precedes it.
            #[cfg(feature = "__test-faults")]
            if self.cfg.indexed.is_some()
                && a.test_directives().fault.as_deref() == Some("indexed-pending")
            {
                return Err(crate::indexed::pending(5_000));
            }
            if !defer_verification {
                (staged, ticket_ms) = self.verify_ticketed_advance(&op, &p, snap).await?;
            }
        } else if let Err(error) = self.check_ticketless_head(&op).await {
            return self
                .store_policy_denial(&op, a, &p, ahead, error, (false, None))
                .await
                .map(|stored| (stored, ResponseMeta::default()));
        }
        if !defer_verification && staged.inspection.is_none() {
            staged.inspection = self
                .inspection_max_objects()
                .map(|limit| crate::indexed::inspection::InspectionSet::new(limit as usize));
        }
        if let Some(pending) = implicit {
            let upd = refs
                .first_mut()
                .ok_or_else(|| internal("implicit consumption needs an UpdateRef"))?;
            // The B10 check may rewrite `Any` to the exact value it
            // observed, so the planned batch guards it.
            self.check_implicit_packmap(&op, pending, ahead.as_ref(), upd)
                .await?;
        }
        let existing = self.begin_decision(&op, a, ahead.as_mut()).await?;
        let consuming = ticketed || implicit.is_some_and(|pending| !pending.is_empty());
        let run_admission = existing.is_none() && !(default_admission && consuming);
        if existing.is_none() && (!ticketed || !default_admission) {
            self.check_outbox_backpressure(&p, ahead.as_ref()).await?;
        }
        let resolved_ref_updates = if run_admission && !default_admission {
            self.resolve_ref_updates(&op, &refs, ahead.as_ref()).await?
        } else {
            Vec::new()
        };
        // Keep the default's existing consumption paths and quota accounting.
        // Custom admission reserves refs separately from the upload's bytes.
        let allowance = if run_admission {
            let credentials = admission::validate_credentials(&a.credential_capture)?;
            let mut input = AdmissionInput::new(&op);
            input.resolved_ref_updates.clone_from(&resolved_ref_updates);
            input.credential_headers = &credentials;
            if let OpKind::BeginUpload { key, bytes, .. } = &op.kind {
                input.declared_bytes = *bytes;
                input.pack_id = Some(*key);
                input.new_to_repo_bytes = self.new_to_repo_bytes(&op, key, *bytes).await?;
            }
            self.admit(input).await?
        } else {
            Allowance::default()
        };
        let pending = match allowance.reservation.as_deref() {
            Some(rid) => Some(
                self.record_pending(a, &p, rid, stored_procedure(&op.kind)?)
                    .await?,
            ),
            None => None,
        };
        let replaced = ReplacedSession::default();
        let write_result = async {
            if defer_verification {
                let snap = ahead
                    .as_ref()
                    .ok_or_else(|| internal("ticket advance requires atomic metadata"))?;
                (staged, ticket_ms) = self.verify_ticketed_advance(&op, &p, snap).await?;
                if staged.inspection.is_none() {
                    staged.inspection = self.inspection_max_objects().map(|limit| {
                        crate::indexed::inspection::InspectionSet::new(limit as usize)
                    });
                }
            }
            let mut begin = self.begin_write(&op, a, existing, allowance.reservation.clone())?;
            self.precheck_namespace(&p, &allowance.charges, &mut ahead, a.business_skew_ms)?;
            let mut opened_session = None;
            if let Some(BeginWrite::Open(open)) = &mut begin
                && open.spec.bytes > open.spec.part_size
            {
                let key = PackKey(open.spec.pack_id).into();
                let ticket_id = crate::store::tickets::ticket_id(&open.spec.reservation_id);
                let session = self
                .blobs
                .begin_multipart_for_ticket(key, open.spec.bytes, open.spec.part_size, ticket_id)
                .await
                .map_err(|e| {
                    if open.reserved() {
                        tracing::warn!(error = %e, "reserved multipart session creation failed");
                        ServerError::unavailable("multipart session creation failed; retry")
                    } else {
                        store_error(StorageOp::MultipartSession, e)
                    }
                })?;
                if session.is_empty() || session.len() > u16::MAX as usize {
                    if let Err(err) = self.blobs.abort(key, &session).await {
                        tracing::warn!(error = %err, "failed to abort invalid multipart session");
                    }
                    return Err(ServerError::internal(
                        "object storage request failed",
                        "multipart store returned an invalid session identifier",
                    ));
                }
                opened_session = Some((key, session.clone(), ticket_id));
                open.spec.upload_session = Some(session);
            }
            let write_result = async {
                let lease = if let Some(observed) = lease {
                    let (created, lease) = {
                        // The native gate serializes same-shard lease grants too.
                        // Read observations remain pre-admission; a waiter rebuilds
                        // a stale coordinator observation within the usual three tries.
                        let _grant_gate = match (&self.gate, &observed) {
                            (Some(gate), lease::LeaseObservation::Renew(_)) => {
                                Some(gate.enter(&p).await)
                            }
                            _ => None,
                        };
                        self.admit_lease(&op, &p, observed, a.business_skew_ms, None)
                            .await?
                    };
                    op.created = created;
                    op.leased_epoch = Some(lease.value.epoch);
                    if lease.install {
                        fault!(self, AfterLeaseGrant, &op, a);
                    }
                    Some(lease)
                } else {
                    op.created = self.commit_creation(&op, a.business_skew_ms).await?;
                    None
                };
                let was_any = ref_policy::subject_is_any(&op, &refs);
                if let Err(error) = self
                    .check_fast_forward(
                        &op,
                        &mut refs,
                        ahead.as_ref(),
                        fast_forward.as_ref(),
                        (&staged, ticket_ms),
                    )
                    .await
                {
                    // An ancestry denial was decided against the exact value the
                    // check pinned; the stored refusal must not outlive it.
                    let denial_ref = ref_policy::pinned_ref_value(&op, &refs, was_any);
                    return self
                        .store_policy_denial(
                            &op,
                            a,
                            &p,
                            ahead,
                            error,
                            (pending.is_some(), denial_ref),
                        )
                        .await;
                }
                self.pre_receive(&op).await?;
                let write = (kind, refs.as_slice(), allowance.charges.as_slice());
                self.plan_and_apply(
                    &op,
                    a,
                    &p,
                    write,
                    ahead,
                    (lease, begin.as_ref()),
                    WriteInputs {
                        resolved_ref_updates: &resolved_ref_updates,
                        denial_ids: &staged.denial_ids,
                        denial_packs: &staged.denial_packs,
                        replaced: &replaced,
                        pending: pending.as_ref(),
                        implicit,
                        external_bases: &staged.external_bases,
                        inspected: staged.inspection.as_mut(),
                    },
                )
                .await
            }
            .await;
            if let Some((key, session, fresh_id)) = opened_session {
                self.cleanup_opened_session(&p, &write_result, key, &session, fresh_id)
                    .await;
            }
            write_result
        }
        .await;
        // After the write gate: object-store latency must not stall the stripe.
        let replaced = replaced
            .into_inner()
            .unwrap_or_else(std::sync::PoisonError::into_inner);
        if let Some((key, session)) = replaced
            && let Err(error) = self.blobs.abort(key, &session).await
        {
            crate::timers::ticket_expiry::record_abort_failure();
            tracing::warn!(%error, "replaced ticket session abort failed");
        }
        if let (Some(pending), Err(err)) = (&pending, &write_result) {
            let (reason, detail) = reservation::abort_reason(err);
            self.resolve_pending(&p, pending, reason, detail).await;
        }
        write_result.map(|result| {
            let committed = matches!(
                &result,
                StoredResult::UpdateRef(UpdateRefResult::Committed)
                    | StoredResult::AdvanceRefs(AdvanceOutcome::Committed)
                    | StoredResult::BeginUpload(BeginUploadResult::Ticket { .. })
            );
            let meta = if committed
                && (!allowance.response_headers.is_empty() || allowance.external_ref.is_some())
            {
                let mut headers = allowance.response_headers;
                if !headers.is_empty() {
                    headers.push(("Cache-Control".into(), "private".into()));
                }
                ResponseMeta {
                    headers,
                    external_ref: allowance.external_ref,
                }
            } else {
                ResponseMeta::default()
            };
            (result, meta)
        })
    }

    async fn cleanup_opened_session(
        &self,
        partition: &Partition,
        result: &Result<StoredResult, ServerError>,
        key: crate::store::BlobKey,
        session: &[u8],
        fresh_id: Hash,
    ) {
        // A ticket-derived storage id can be shared by two attempts in the
        // same replay scope. The loser must leave it for the winning ticket;
        // if neither commits, the session contains only meta until the sweep.
        if session == fresh_id {
            return;
        }
        // A raced Existing ticket can have the same reservation-derived id
        // with a different session. Compare the authenticated answer.
        let committed_fresh = match result {
            Ok(StoredResult::BeginUpload(BeginUploadResult::Ticket { id, token, .. }))
                if *id == fresh_id =>
            {
                self.cfg
                    .ticket_keys
                    .as_ref()
                    .and_then(|keys| keys.verify(token, 0).ok())
                    .is_some_and(|claims| claims.upload_session == session)
            }
            _ => false,
        };
        // An apply can commit and then lose its acknowledgement. Check the
        // row before reclaiming; an unavailable or corrupt read is ambiguous.
        let stored_fresh = if result.is_err() {
            match self.meta.get(partition, &keys::ticket(&fresh_id)).await {
                Ok(Some(raw)) => codec::decode_ticket(&raw)
                    .ok()
                    .is_none_or(|ticket| ticket.upload_session.as_deref() == Some(session)),
                Ok(None) => false,
                Err(err) => {
                    tracing::warn!(error = %err, "could not confirm multipart ticket after failed write");
                    true
                }
            }
        } else {
            false
        };
        if !committed_fresh
            && !stored_fresh
            && let Err(err) = self.blobs.abort(key, session).await
        {
            tracing::warn!(error = %err, "failed to abort unused multipart session");
        }
    }

    /// Stage 1: the typed operation, for the procedure `a` was
    /// authenticated for only.
    fn identify(&self, a: &Authenticated, kind: OpKind) -> Result<Operation, ServerError> {
        if a.procedure() != kind.procedure() {
            return Err(ServerError::unauthenticated(
                "credentials were checked for another procedure",
            ));
        }
        if matches!(self.cfg.auth, AuthMode::AuthV2(_))
            && kind.procedure().is_write()
            && kind.procedure() != Procedure::SetRepoVisibility
            && a.auth.is_none()
        {
            return Err(ServerError::unauthenticated(
                "missing auth v2 authorization",
            ));
        }
        let repo = a.repo().repo.clone();
        let principal = a.principal.clone();
        let mut op = Operation::new(repo, principal, a.auth.clone(), kind);
        op.write_grant.clone_from(&a.write_grant);
        op.business_now_ms = Some(a.business_now_ms);
        Ok(op)
    }

    /// Multi reads require a repository registered in the namespace coordinator.
    async fn require_repository<S: NamespaceStore>(
        &self,
        repo: &crate::repo::RepoId,
        meta: &S,
    ) -> Result<(), ServerError> {
        if matches!(self.cfg.addressing, Addressing::Multi(_)) {
            let p = self.shards.coordinator(&repo.namespace);
            let value = meta
                .get(&p, &keys::repo_record(&repo.name))
                .await
                .map_err(meta_error)?;
            match value {
                Some(value) => {
                    codec::decode_repo_record(&value).map_err(meta_error)?;
                }
                None => return Err(ServerError::repository_not_found()),
            }
        }
        Ok(())
    }

    /// Whether repository visibility (`rv` rows) gates reads: a Multi,
    /// owner-policy, auth v2 deployment (SPEC-WRITE-GRANTS §9.1).
    fn visibility_applies(&self) -> bool {
        matches!(self.cfg.addressing, Addressing::Multi(_))
            && self.cfg.write_policy == WritePolicy::Owner
            && matches!(self.cfg.auth, AuthMode::AuthV2(_))
    }

    /// Whether a stored `rv = private` gates reads: any Multi
    /// owner-policy deployment, whatever its auth mode. A pipeline that
    /// cannot verify a signer (a non-auth-v2 sibling) reads every private
    /// repository as `not_found`.
    fn visibility_gates_reads(&self) -> bool {
        matches!(self.cfg.addressing, Addressing::Multi(_))
            && self.cfg.write_policy == WritePolicy::Owner
    }

    /// Stage 2 for a read. Under [`Self::visibility_gates_reads`], one
    /// coordinator `get_many` reads `rr`, `rv` and `e`; a private
    /// repository denies unauthorized reads with the same `not_found` as a
    /// missing one (SPEC-WRITE-GRANTS §9.3). The returned facts carry the
    /// caller's view; `epoch` is the stored grant epoch, for
    /// `IssueObjectUrl`'s reuse.
    async fn authorize_read(&self, op: &Operation) -> Result<ReadAuth, ServerError> {
        let authorization = self.authorize_read_with_meta(op, &self.meta, None);
        if op.auth.is_some()
            && matches!(self.cfg.addressing, Addressing::Multi(_))
            && matches!(
                op.kind,
                OpKind::PackExists { .. } | OpKind::DownloadPack { .. }
            )
        {
            let (result, ()) =
                futures::future::join(authorization, self.meta.prepare_repo_read(&op.repo)).await;
            result
        } else {
            authorization.await
        }
    }

    async fn authorize_read_with_meta<S: NamespaceStore>(
        &self,
        op: &Operation,
        meta: &S,
        read_cap_message: Option<&'static str>,
    ) -> Result<ReadAuth, ServerError> {
        tracing::debug!(stage = "authorize");
        if !self.visibility_gates_reads() {
            return self.authorize_read_ungated(op, meta).await;
        }
        // §7 steps 1–10 are stateless: run them before the coordinator
        // read, even when the repository turns out to be missing.
        let admin_owner = Namespace::parse(op.repo.namespace.as_str())
            .is_ok_and(|namespace| self.owner_key_is_admin(&namespace));
        let check = op
            .write_grant
            .as_ref()
            .filter(|_| !admin_owner)
            .and_then(|header| {
                self.cfg
                    .grants
                    .as_ref()
                    .and_then(|g| read_policy::check_grant(g, header.expose(), op))
            });
        let signed = op.auth.is_some();
        let owner = op.write_grant.is_none() && self.namespace_owner(&op.repo, &op.principal);
        let Some((private, epoch)) = self
            .read_repo_state(&op.repo, meta, read_cap_message)
            .await?
        else {
            // A missing repository pays the hook round trip a private one
            // would, and discards it, so latency does not tell them apart.
            if signed && op.write_grant.is_none() {
                let provisional = AuthzFacts {
                    authority_generation: None,
                    grant: None,
                    owner,
                    caller_view: if owner {
                        CallerView::Writer
                    } else {
                        CallerView::Reader
                    },
                };
                let _ = self.read_hook(op, true, true, &provisional).await;
            }
            return Err(ServerError::repository_not_found());
        };
        // §7 step 11: the grant's epoch must equal the stored epoch.
        let grant = check.filter(|c| c.epoch == epoch);
        let grant_ref = grant.map(|c| GrantRef {
            id: c.id,
            epoch,
            // Ref-scope presence constraints govern writes only.
            presence_requirement: None,
        });
        let authority = self.cfg.authorizer_role == AuthorizerRole::Authority;
        if private && !signed {
            return Err(ServerError::repository_not_found());
        }
        let provisional = AuthzFacts {
            authority_generation: None,
            grant: grant_ref.clone(),
            owner,
            caller_view: if owner || grant.is_some_and(|g| g.write) {
                CallerView::Writer
            } else {
                CallerView::Reader
            },
        };
        let hook = self.read_hook(op, private, signed, &provisional).await?;
        let caller = read_policy::Caller {
            #[cfg(feature = "http-objects")]
            http_token_authorized: false,
            signed,
            owner,
            grant: grant.map(|g| read_policy::GrantEval {
                read: g.read,
                write: g.write,
            }),
            hook,
            authority,
        };
        match read_policy::decide(op.procedure(), private, caller) {
            read_policy::ReadDecision::NotFound => Err(ServerError::repository_not_found()),
            read_policy::ReadDecision::Allow(caller_view) => Ok(ReadAuth {
                facts: AuthzFacts {
                    authority_generation: None,
                    grant: grant_ref,
                    owner,
                    caller_view,
                },
                epoch: Some(epoch),
            }),
        }
    }

    /// One coordinator `get_many` for the `rr`, `rv` and `e` rows of a
    /// read: `Some((private, epoch))`. A missing `rr` is `None`
    /// (the caller answers the uniform `not_found`). Backend failures remain
    /// `unavailable`; a caller-budget refusal is `resource_exhausted`.
    async fn read_repo_state<S: NamespaceStore>(
        &self,
        repo: &crate::repo::RepoId,
        meta: &S,
        read_cap_message: Option<&'static str>,
    ) -> Result<Option<(bool, u64)>, ServerError> {
        let coordinator = self.shards.coordinator(&repo.namespace);
        let rows = meta
            .get_many(
                &coordinator,
                &[
                    keys::repo_record(&repo.name),
                    keys::repo_visibility(&repo.name),
                    keys::grant_epoch(),
                ],
            )
            .await
            .map_err(|e| {
                tracing::warn!(detail = %e, "repository state read failed");
                if crate::indexed::budget::is_exhausted(&e) {
                    // Reader URL issuance chooses its stable cap message here;
                    // typed hook errors never need reclassification later.
                    ServerError::resource_exhausted(
                        read_cap_message.unwrap_or("repository state call budget exhausted"),
                    )
                } else {
                    ServerError::unavailable("repository state unavailable")
                }
            })?;
        let mut rows = rows.into_iter();
        let Some(record) = rows.next().flatten() else {
            return Ok(None);
        };
        codec::decode_repo_record(&record).map_err(meta_error)?;
        let stored = rows
            .next()
            .flatten()
            .map(|v| codec::decode_repo_visibility(&v))
            .transpose()
            .map_err(meta_error)?;
        let epoch = rows
            .next()
            .flatten()
            .map(|v| codec::decode_u64(&v))
            .transpose()
            .map_err(meta_error)?
            .unwrap_or(0);
        Ok(Some((
            repo_is_private(stored.as_ref(), self.cfg.default_repo_visibility),
            epoch,
        )))
    }

    /// Consult the authorizer for a read on an existing repository under
    /// `visibility_gates_reads`: on a private repository its verdict can
    /// authorize the read; on a public one it only classifies the caller
    /// (`Authority`) or checks the read as before (`Check`, error
    /// propagates). `provisional` are the facts the hook sees.
    async fn read_hook(
        &self,
        op: &Operation,
        private: bool,
        signed: bool,
        provisional: &AuthzFacts,
    ) -> Result<read_policy::HookEval, ServerError> {
        let authorized = || {
            let mut authorized = op.clone();
            authorized.authz = provisional.clone();
            authorized
        };
        let writer = |facts: &AuthzFacts| facts.caller_view == CallerView::Writer;
        if private {
            if op.write_grant.is_some() {
                // A presented grant is the only path to a private read
                // (§6, §9.3): the hook never authorizes it.
                return Ok(read_policy::HookEval::NotConsulted);
            }
            return Ok(
                match self.hooks.authorizer().authorize(&authorized()).await {
                    Ok(facts) => read_policy::HookEval::Allow {
                        writer_view: writer(&facts),
                    },
                    // Any hook error, `unavailable` included, denies so the
                    // read cannot reveal that the repository exists (§9.3).
                    Err(_) => read_policy::HookEval::Deny,
                },
            );
        }
        if self.cfg.authorizer_role == AuthorizerRole::Authority {
            // Classification only: an unsigned caller or an established
            // writer needs no hook; a hook error keeps the reader view.
            if !signed || provisional.caller_view == CallerView::Writer {
                return Ok(read_policy::HookEval::NotConsulted);
            }
            return Ok(
                match self.hooks.authorizer().authorize(&authorized()).await {
                    Ok(facts) => read_policy::HookEval::Allow {
                        writer_view: writer(&facts),
                    },
                    Err(_) => read_policy::HookEval::NotConsulted,
                },
            );
        }
        // Check role: the hook sees the read as before; it cannot confer
        // a view.
        self.hooks
            .authorizer()
            .authorize(op)
            .await
            .map_err(ServerError::strip_admission_shape)?;
        Ok(read_policy::HookEval::NotConsulted)
    }

    /// The read path when [`Self::visibility_gates_reads`] does not hold: the
    /// hook decides, then the `rr` row gates existence (Multi only). The
    /// caller's view comes from its principal and the write policy.
    async fn authorize_read_ungated<S: NamespaceStore>(
        &self,
        op: &Operation,
        meta: &S,
    ) -> Result<ReadAuth, ServerError> {
        let facts = self
            .hooks
            .authorizer()
            .authorize(op)
            .await
            .map_err(ServerError::strip_admission_shape)?;
        self.require_repository(&op.repo, meta).await?;
        let caller_view = match &op.principal {
            Principal::Anonymous => CallerView::Anonymous,
            Principal::BearerHolder => CallerView::Reader,
            principal => {
                if self.cfg.write_policy == WritePolicy::Open
                    || self.namespace_owner(&op.repo, principal)
                {
                    CallerView::Writer
                } else {
                    CallerView::Reader
                }
            }
        };
        Ok(ReadAuth {
            facts: AuthzFacts {
                caller_view,
                ..facts
            },
            epoch: None,
        })
    }

    async fn pack_is_member(
        &self,
        a: &Authenticated,
        key: &PackKey,
        caller: CallerView,
    ) -> Result<bool, ServerError> {
        if matches!(self.cfg.addressing, Addressing::Single { .. }) {
            return Ok(true);
        }
        let view = crate::store::view::ViewStore {
            store: &self.meta,
            repo: &a.repo().repo,
            writer: caller == CallerView::Writer,
            policy: self.publication_policy.as_deref(),
        };
        let member = read::is_member(
            &view,
            self.shards.as_ref(),
            &a.repo().repo,
            &key.0,
            a.ref_hint.as_deref(),
        )
        .await
        .map_err(meta_error)?;
        if member && self.cfg.indexed.is_some() {
            match crate::takedown::denial::require_clear(
                &crate::store::DenialReads::new(&self.meta, self.cfg.takedown_denial),
                &key.0,
            )
            .await
            {
                Ok(()) => {}
                Err(e) if e.public_message() == "object blocked" => return Ok(false),
                Err(e) => return Err(e),
            }
        }
        if member && self.cfg.takedown_denial && self.cfg.indexed.is_some() {
            return match crate::takedown::denial::require_pack_clear(
                &self.meta,
                self.shards.as_ref(),
                &a.repo().repo,
                &key.0,
            )
            .await
            {
                Ok(()) => Ok(true),
                Err(e) if e.public_message() == "object blocked" => Ok(false),
                Err(e) => Err(e),
            };
        }
        Ok(member)
    }

    /// A unary write's ref writes in decision order (packmap first) and
    /// the ref shard they commit in, which a head and its packmap share.
    fn ref_writes(
        &self,
        op: &Operation,
    ) -> Result<(WriteKind, Vec<RefUpdate>, Partition), ServerError> {
        let (kind, refs) = match &op.kind {
            OpKind::UpdateRef(u) => (WriteKind::UpdateRef, vec![u.clone()]),
            OpKind::AdvanceRefs { head, packmap, .. } => {
                (WriteKind::AdvanceRefs, vec![packmap.clone(), head.clone()])
            }
            OpKind::BeginUpload { ref_name, .. } => {
                return Ok((
                    WriteKind::BeginUpload,
                    vec![],
                    self.shards.ref_shard(&op.repo, ref_name),
                ));
            }
            _ => return Err(internal("not a unary write")),
        };
        let p = self.shards.ref_shard(&op.repo, &refs[0].name);
        if refs
            .iter()
            .any(|r| self.shards.ref_shard(&op.repo, &r.name) != p)
        {
            return Err(internal("shard map splits a head from its packmap"));
        }
        Ok((kind, refs, p))
    }

    /// One `get_many` before any hook, on an atomic store: the write's
    /// refs and layout version, and for a signed write its replay record,
    /// the grant epoch and the default quota key it will most likely be
    /// charged. Keys admission adds later are read after it.
    async fn read_ahead(
        &self,
        op: &Operation,
        p: &Partition,
        refs: &[RefUpdate],
        business_skew_ms: i64,
    ) -> Result<Option<Snapshot>, ServerError> {
        let caps = self.meta.capabilities();
        if !caps.atomic_multi_key {
            return Ok(None);
        }
        let namespace_window = if matches!(self.cfg.addressing, Addressing::Multi(_))
            && self.hooks.admission().is_default()
        {
            self.cfg.write_quota.map(|limits| {
                quota::namespace_window(
                    self.clock.now_ms().saturating_add(business_skew_ms),
                    limits.window_ms,
                )
            })
        } else {
            None
        };
        let mut wanted: Vec<Key> = refs
            .iter()
            .map(|r| keys::ref_key(&op.repo.name, &r.name))
            .collect();
        if let Some(update) = refs.first() {
            let name = crate::store::publication::sequence_ref(&update.name);
            wanted.push(keys::publication(&op.repo.name, &name));
            wanted.push(keys::ref_key(&op.repo.name, &name));
            if let Some(packmap) = mkit_attest::grant::head_packmap(&name) {
                wanted.push(keys::ref_key(&op.repo.name, &packmap));
            }
            wanted.push(keys::outbox_sequence());
        }
        if self.cfg.sharding == Sharding::Single && caps.key_classes == KeyClasses::All {
            wanted.extend([keys::authority_generation(), keys::lease_recovery()]);
        }
        if caps.implicit_layout_version.is_none() {
            wanted.push(keys::layout_version());
        }
        wanted.push(keys::outcome_backlog());
        if matches!(self.cfg.addressing, Addressing::Multi(_)) {
            wanted.push(keys::repo_known(&op.repo.name));
        }
        if self.cfg.sharding == Sharding::D34 {
            if matches!(p, Partition::Coordinator(_)) {
                wanted.push(keys::fork_barrier(&op.repo.name));
            }
            wanted.push(keys::epoch_lease());
            if !refs.is_empty() {
                wanted.push(keys::outbox_sequence());
            }
        }
        if let Some(auth) = &op.auth {
            wanted.push(keys::replay(&auth.replay_scope));
            if self.cfg.sharding == Sharding::Single {
                wanted.push(keys::grant_epoch());
            }
            if self.cfg.write_quota.is_some() {
                let scope = QuotaScope::for_signer(&op.repo.namespace, &auth.signer);
                wanted.push(keys::quota(&scope));
            }
            if let (Some(window), Some(limits)) = (namespace_window, self.cfg.write_quota) {
                let charge = NamespaceCharge {
                    limits,
                    window,
                    bytes: 0,
                    rollup: matches!(p, Partition::Ref { .. }),
                };
                wanted.push(quota::counter_key(charge, window));
                if charge.rollup {
                    wanted.push(keys::quota_view(window));
                }
                // Admission may run after the current window ends. Fetch the
                // next window in the same read-ahead call, before any lease.
                let next = window.saturating_add(1);
                wanted.push(quota::counter_key(charge, next));
                if charge.rollup {
                    wanted.push(keys::quota_view(next));
                }
            }
        }
        if let OpKind::BeginUpload { ref_name, key, .. } = &op.kind {
            let signer = op
                .auth
                .as_ref()
                .ok_or_else(|| internal("missing ticket signer"))?
                .signer;
            wanted.extend(begin::decision_keys(
                &op.repo.name,
                ref_name,
                &key.0,
                &signer,
            )?);
        }
        let mut snap = Snapshot::default();
        snap.namespace_window = namespace_window;
        self.fill(p, &mut snap, wanted).await?;
        Ok(Some(snap))
    }

    fn namespace_charge(
        &self,
        p: &Partition,
        charges: &[QuotaCharge],
        window: Option<u64>,
    ) -> Result<Option<NamespaceCharge>, ServerError> {
        if !matches!(self.cfg.addressing, Addressing::Multi(_))
            || !self.hooks.admission().is_default()
        {
            return Ok(None);
        }
        let Some(charge) = charges.first() else {
            return Ok(None);
        };
        let window = window.ok_or_else(|| internal("namespace quota read-ahead missing"))?;
        Ok(Some(NamespaceCharge {
            limits: charge.limits,
            window,
            bytes: charge.bytes,
            rollup: matches!(p, Partition::Ref { .. }),
        }))
    }

    /// Reject a namespace cap before a lease or multipart session is made.
    /// The planner repeats the guarded check when it commits the write.
    fn precheck_namespace(
        &self,
        p: &Partition,
        charges: &[QuotaCharge],
        ahead: &mut Option<Snapshot>,
        business_skew_ms: i64,
    ) -> Result<(), ServerError> {
        let Some(mut charge) = self.namespace_charge(
            p,
            charges,
            ahead
                .as_ref()
                .and_then(|snapshot| snapshot.namespace_window),
        )?
        else {
            return Ok(());
        };
        let now = self.clock.now_ms().saturating_add(business_skew_ms);
        let window = quota::namespace_window(now, charge.limits.window_ms);
        if window != charge.window && window != charge.window.saturating_add(1) {
            return Err(
                ServerError::aborted_retryable("namespace quota window advanced; retry")
                    .with_abort_cause(AbortCause::QuotaWindow),
            );
        }
        charge.window = window;
        let snap = ahead
            .as_mut()
            .ok_or_else(|| internal("namespace quota needs atomic reads"))?;
        let stored_view = charge
            .rollup
            .then(|| snap.get(&keys::quota_view(window)))
            .flatten();
        let seeded_view = snap
            .namespace_seed
            .as_ref()
            .filter(|(seed_window, _)| *seed_window == window)
            .map(|(_, value)| value);
        let decision = quota::check_namespace(
            snap.get(&quota::counter_key(charge, window)),
            stored_view.or(seeded_view),
            now,
            charge,
        )?;
        match decision {
            NamespaceDecision::Exhausted => {
                return Err(ServerError::resource_exhausted(
                    "namespace write op/byte quota exceeded for this window; try again later",
                ));
            }
            NamespaceDecision::Allowed {
                view: ViewStatus::Missing,
                ..
            } => self.metrics.incr(
                crate::telemetry::METRIC_NAMESPACE_QUOTA_VIEW_FALLBACK,
                &[("state", "missing")],
                1,
            ),
            NamespaceDecision::Allowed {
                view: ViewStatus::Stale,
                ..
            } => self.metrics.incr(
                crate::telemetry::METRIC_NAMESPACE_QUOTA_VIEW_FALLBACK,
                &[("state", "stale")],
                1,
            ),
            NamespaceDecision::Allowed { .. } => {}
        }
        snap.namespace_window = Some(window);
        Ok(())
    }

    /// Read every key of `wanted` that `snap` lacks, in one `get_many`.
    async fn fill(
        &self,
        p: &Partition,
        snap: &mut Snapshot,
        wanted: Vec<Key>,
    ) -> Result<(), ServerError> {
        self.fill_with(&self.meta, p, snap, wanted).await
    }

    async fn fill_with<S: NamespaceStore>(
        &self,
        meta: &S,
        p: &Partition,
        snap: &mut Snapshot,
        mut wanted: Vec<Key>,
    ) -> Result<(), ServerError> {
        wanted.retain(|k| !snap.contains(k));
        wanted.sort();
        wanted.dedup();
        if wanted.is_empty() {
            return Ok(());
        }
        let values = meta.get_many(p, &wanted).await.map_err(meta_error)?;
        for (key, value) in wanted.into_iter().zip(values) {
            snap.insert(key, value);
        }
        Ok(())
    }

    /// Stage 0 lookup: a signed write's replay record, from the read-ahead
    /// and before any hook. A committed record's result is returned, an
    /// in-flight one is `aborted`; a new operation continues.
    fn replay_lookup(
        op: &Operation,
        ahead: Option<&Snapshot>,
    ) -> Result<Option<StoredResult>, ServerError> {
        let (Some(auth), Some(snap)) = (&op.auth, ahead) else {
            return Ok(None);
        };
        tracing::debug!(stage = "replay_lookup");
        let stored = snap.get(&keys::replay(&auth.replay_scope));
        let record = stored.map(codec::decode_replay_record).transpose();
        let record = record.map_err(meta_error)?;
        replay_answer(classify(record.as_ref(), &auth.fingerprint))
    }

    fn merge_authority_facts(
        &self,
        built_in: &mut AuthzFacts,
        returned: &AuthzFacts,
    ) -> Result<(), ServerError> {
        if self.cfg.authorizer_role == AuthorizerRole::Authority
            && self.cfg.authority_fence.is_some()
        {
            built_in.authority_generation =
                Some(returned.authority_generation.ok_or_else(|| {
                    ServerError::unavailable("Authority allowance missing generation")
                })?);
        }
        Ok(())
    }

    /// Stage 2: the facts it returns become `op.authz` before admission.
    async fn authorize(
        &self,
        op: &Operation,
    ) -> Result<(AuthzFacts, Option<FastForward>), ServerError> {
        tracing::debug!(stage = "authorize");
        if !op.procedure().is_write() {
            return Ok((self.authorize_read(op).await?.facts, None));
        }
        if self.cfg.authority_fence.is_some() && self.cfg.sharding == Sharding::Single {
            Box::pin(self.ensure_authority_activation(&op.repo.namespace)).await?;
        } else if self.cfg.namespace_mode == crate::namespace::NamespaceMode::Authority {
            // Leased sharding activates in `observe_lease`; refuse an
            // unregistered namespace before the hook or Admission on every path.
            self.require_registered(&op.repo.namespace).await?;
        }
        match &self.cfg.addressing {
            Addressing::Multi(multi) => self.owner_rule(op, Some(&multi.namespace_policy)).await,
            // Owner on a namespaced Single is the ssh root mode's rule;
            // Open Single is the authorizer's alone, unchanged.
            Addressing::Single { .. } if self.cfg.write_policy == WritePolicy::Owner => {
                self.owner_rule(op, None).await
            }
            Addressing::Single { .. } => self
                .hooks
                .authorizer()
                .authorize(op)
                .await
                .map(|mut facts| {
                    // The authority fence is valid only for Multi addressing.
                    // A hook cannot activate it on an unfenced Single deployment.
                    facts.authority_generation = None;
                    (facts, None)
                })
                .map_err(ServerError::strip_admission_shape),
        }
    }

    fn namespace_owner(&self, repo: &RepoId, principal: &Principal) -> bool {
        self.cfg.namespace_mode == crate::namespace::NamespaceMode::SelfCertifying
            && matches!(Namespace::parse(repo.namespace.as_str()), Ok(Namespace::Ed25519(key)) if principal.ed25519() == Some(&key))
    }

    fn owner_key_is_admin(&self, namespace: &Namespace) -> bool {
        self.cfg.namespace_mode == crate::namespace::NamespaceMode::SelfCertifying
            && matches!(namespace, Namespace::Ed25519(key) if self.cfg.admin_keys.contains(key))
    }

    fn require_client_owner_key(&self, namespace: &Namespace) -> Result<(), ServerError> {
        if self.owner_key_is_admin(namespace) {
            return Err(ServerError::permission_denied(
                "admin key cannot authorize client calls",
            ));
        }
        Ok(())
    }

    /// SPEC-TRANSPORT-CONNECT §7.5 rule 1: an allowlisted namespace whose
    /// principal owns it (`ed25519-<key>` ↔ the Ed25519 principal), and the
    /// M2 write grants that qualify it. `policy` is the deployment's
    /// `NamespacePolicy` on Multi and `None` on an Owner-policy Single —
    /// the `None` counts as "not an allowlist" for the 0x-plus-grant rule,
    /// which denies fail closed. The authorizer hook sees the established
    /// facts on success; under `Check` a non-owner never reaches it.
    async fn owner_rule(
        &self,
        op: &Operation,
        policy: Option<&NamespacePolicy>,
    ) -> Result<(AuthzFacts, Option<FastForward>), ServerError> {
        if self.cfg.namespace_mode == crate::namespace::NamespaceMode::Authority {
            self.cfg
                .namespace_mode
                .namespace(op.repo.namespace.as_str())
                .map_err(|_| internal("invalid resolved authority namespace"))?;
            if op.write_grant.is_some() {
                return Err(crate::namespace::owner_statements_refused());
            }
            let mut authorized = op.clone();
            authorized.authz = AuthzFacts {
                caller_view: CallerView::Reader,
                ..AuthzFacts::default()
            };
            let returned = self
                .hooks
                .authorizer()
                .authorize(&authorized)
                .await
                .map_err(ServerError::strip_admission_shape)?;
            self.merge_authority_facts(&mut authorized.authz, &returned)?;
            authorized.authz.caller_view = CallerView::Writer;
            return Ok((authorized.authz, None));
        }
        let namespace = Namespace::parse(op.repo.namespace.as_str())
            .map_err(|_| internal("invalid resolved owner-policy namespace"))?;
        if op.write_grant.is_some() {
            self.require_client_owner_key(&namespace)?;
        }
        if let Some(NamespacePolicy::Allowlist(allowed)) = policy
            && !allowed.contains(&namespace)
        {
            return Err(ServerError::permission_denied("write not permitted"));
        }
        if op.write_grant.is_some()
            && matches!(namespace, Namespace::Address(_))
            && !matches!(policy, Some(NamespacePolicy::Allowlist(_)))
        {
            return Err(ServerError::permission_denied("write not permitted"));
        }
        let mut fast_forward = None;
        let grant = if let Some(header) = &op.write_grant {
            let cfg = self.cfg.grants.as_ref().ok_or_else(|| {
                grants::rejected(mkit_attest::grant::GrantError::SchemeNotAdvertised)
            })?;
            let verified = cfg.verify(header.expose(), op)?;
            // Step 8 (ref scope) before step 11, which reads state and comes last.
            let scope =
                crate::policy::ref_scopes::authorize(&verified, &op.kind, self.cfg.indexed_mode())?;
            fast_forward = scope.fast_forward;
            let presence_requirement = scope.presence;
            let observed = match self.cfg.sharding {
                Sharding::Single => op.observed_epoch,
                Sharding::D34 => op.leased_epoch,
            };
            if observed != Some(verified.epoch()) {
                return Err(plan::epoch_moved());
            }
            tracing::debug!(grant_id = %to_hex_bytes(verified.id()), "write grant accepted");
            Some(crate::op::GrantRef {
                id: *verified.id(),
                epoch: verified.epoch(),
                presence_requirement,
            })
        } else {
            None
        };
        let owner = grant.is_none()
            && matches!(&namespace, Namespace::Ed25519(key)
            if op.principal.ed25519() == Some(key));
        // Over ssh/enc (no grant header) a 0x namespace has no owner, so
        // its writes stay denied until WP-2.12.
        if self.cfg.authorizer_role == AuthorizerRole::Check && !owner && grant.is_none() {
            return Err(ServerError::permission_denied("write not permitted"));
        }
        let mut facts = AuthzFacts {
            authority_generation: None,
            grant,
            owner,
            caller_view: CallerView::Writer,
        };
        // Both Authorize and Admit see the established owner/grant facts (§6.2).
        let mut authorized = op.clone();
        authorized.authz = facts.clone();
        let returned = self
            .hooks
            .authorizer()
            .authorize(&authorized)
            .await
            .map_err(ServerError::strip_admission_shape)?;
        self.merge_authority_facts(&mut facts, &returned)?;
        Ok((facts, fast_forward))
    }

    /// Stage 5 (no pack on a unary write).
    async fn pre_receive(&self, op: &Operation) -> Result<(), ServerError> {
        tracing::debug!(stage = "pre_receive");
        self.hooks
            .pre_receive()
            .check(op, None)
            .await
            .map_err(ServerError::strip_admission_shape)
    }

    /// Stages 4 and 6: plan and apply, as one batch on an atomic store or
    /// as sequential single-ref batches on a non-atomic one.
    #[allow(clippy::too_many_lines)] // One request ledger spans prepare and apply.
    async fn plan_and_apply(
        &self,
        op: &Operation,
        a: &Authenticated,
        p: &Partition,
        (kind, refs, charges): (WriteKind, &[RefUpdate], &[QuotaCharge]),
        ahead: Option<Snapshot>,
        (lease, begin): (Option<lease::LeaseWrite>, Option<&BeginWrite>),
        inputs: WriteInputs<'_>,
    ) -> Result<StoredResult, ServerError> {
        let WriteInputs {
            resolved_ref_updates,
            replaced,
            denial_ids,
            denial_packs,
            pending,
            implicit,
            external_bases,
            inspected,
        } = inputs;
        let caps = self.meta.capabilities();
        let replay = upload::replay_guard(op);
        // Single's packs live in the repo directory itself; only Multi
        // plans `m` rows and relay for the consumed set, and only when
        // the set is non-empty (L2).
        let implicit = implicit.filter(|pending| {
            !pending.is_empty() && matches!(self.cfg.addressing, Addressing::Multi(_))
        });
        let implicit_ids = implicit.map(implicit::implicit_packs);
        let implicit_counted = implicit.map(implicit::implicit_counted);
        let advance = self.publication_ticket_write(op, a, p)?;
        let mut req = WriteRequest {
            denial_ids: Some(denial_ids),
            denial_packs,
            fork_barrier: false,
            authority_store: plan::AuthorityStore::from_capabilities(self.meta.capabilities()),
            authority_generation: op.authz.authority_generation,
            namespace: op.repo.namespace.clone(),
            repo: &op.repo.name,
            kind,
            refs,
            resolved_ref_updates,
            ref_index: (self.cfg.sharding == Sharding::D34 && !refs.is_empty()).then_some((
                &op.repo,
                p,
                self.shards.as_ref(),
            )),
            replay,
            charges,
            namespace_charge: self.namespace_charge(
                p,
                charges,
                ahead.as_ref().and_then(|s| s.namespace_window),
            )?,
            grant: op.authz.grant.clone(),
            lease,
            layout_version: caps.implicit_layout_version.is_none(),
            mark_repo_known: matches!(self.cfg.addressing, Addressing::Multi(_))
                && ahead
                    .as_ref()
                    .is_none_or(|snap| snap.get(&keys::repo_known(&op.repo.name)).is_none()),
            rejection: None,
            denial_ref: None,
            publication: (caps.atomic_multi_key && !refs.is_empty()).then_some(
                clearance::PublicationWrite {
                    repo: &op.repo,
                    source: p,
                    shards: self.shards.as_ref(),
                    prepared: None,
                    bound: None,
                },
            ),
            pending,
            begin,
            advance,
            implicit: implicit_ids.as_deref().map(|packs| ImplicitConsume {
                packs,
                counted: implicit_counted.as_deref().unwrap_or_default(),
                repo_id: &op.repo,
                source: p,
                shards: self.shards.as_ref(),
            }),
        };
        let mut ahead = ahead;
        let budget = publication_budget::PublicationBudget::new();
        let prepared = match Box::pin(self.prepare_publication(
            op,
            &a.repo().identity,
            p,
            &req,
            &mut ahead,
            implicit_ids.as_deref(),
            external_bases,
            inspected,
            &budget,
        ))
        .await
        {
            Ok(prepared) => prepared,
            Err(error)
                if self.inspection_max_objects().is_some()
                    && error.code() == crate::Code::PermissionDenied =>
            {
                return self
                    .store_policy_denial(op, a, p, ahead, error, (pending.is_some(), None))
                    .await;
            }
            Err(error) => return Err(error),
        };
        if let (Some(publication), Some((advance, bound))) = (&mut req.publication, &prepared) {
            publication.prepared = Some(advance);
            publication.bound = Some(*bound);
        }
        if caps.atomic_multi_key || replay.is_some() || !charges.is_empty() {
            return self
                .apply_atomic(op, a, p, &req, ahead, (Some(&budget), replaced))
                .await;
        }
        self.apply_sequential(op, a, p, req, &budget, replaced)
            .await
    }

    async fn apply_sequential(
        &self,
        op: &Operation,
        a: &Authenticated,
        p: &Partition,
        mut req: WriteRequest<'_>,
        budget: &publication_budget::PublicationBudget,
        replaced: &ReplacedSession,
    ) -> Result<StoredResult, ServerError> {
        // `Transport::advance_refs`'s default: packmap first, then head.
        let kind = req.kind;
        let refs = req.refs;
        req.kind = WriteKind::UpdateRef;
        for (i, update) in refs.iter().enumerate() {
            req.refs = core::slice::from_ref(update);
            let result = self
                .apply_loop(op, a, p, &req, None, (Some(budget), replaced))
                .await?;
            if let StoredResult::UpdateRef(UpdateRefResult::Conflict { .. }) = result {
                if kind == WriteKind::UpdateRef {
                    return Ok(result);
                }
                return Ok(StoredResult::AdvanceRefs(if i == 0 {
                    AdvanceOutcome::PackmapConflict
                } else {
                    AdvanceOutcome::HeadConflict
                }));
            }
        }
        Ok(match kind {
            WriteKind::UpdateRef => StoredResult::UpdateRef(UpdateRefResult::Committed),
            _ => StoredResult::AdvanceRefs(AdvanceOutcome::Committed),
        })
    }

    fn publication_ticket_write<'a>(
        &'a self,
        op: &'a Operation,
        a: &'a Authenticated,
        p: &'a Partition,
    ) -> Result<Option<advance::AdvanceWrite<'a>>, ServerError> {
        Ok(match &op.kind {
            OpKind::AdvanceRefs { head, tickets, .. } if !tickets.is_empty() => {
                Some(advance::AdvanceWrite {
                    ids: tickets,
                    signer: op
                        .auth
                        .as_ref()
                        .ok_or_else(|| {
                            ServerError::failed_precondition("invalid or expired upload ticket")
                        })?
                        .signer,
                    head_ref: &head.name,
                    repo_id: &op.repo,
                    repository: &a.repo().identity,
                    source: p,
                    shards: self.shards.as_ref(),
                    count_storage: matches!(self.cfg.addressing, Addressing::Multi(_)),
                })
            }
            _ => None,
        })
    }

    /// Prepare inspection against the complete resulting pair before any write.
    #[allow(clippy::too_many_arguments, clippy::too_many_lines)] // Carry authenticated wire identity and ticket lag context.
    async fn prepare_publication(
        &self,
        op: &Operation,
        repository: &str,
        p: &Partition,
        req: &WriteRequest<'_>,
        ahead: &mut Option<Snapshot>,
        implicit_ids: Option<&[Hash]>,
        external_bases: &std::collections::BTreeSet<Hash>,
        inspected: Option<&mut crate::indexed::inspection::InspectionSet>,
        budget: &publication_budget::PublicationBudget,
    ) -> Result<Option<(crate::store::publication::Advance, clearance::PreparedAt)>, ServerError>
    {
        #[cfg(not(feature = "remote-hooks"))]
        let _ = repository;
        // Deletions establish an immediate boundary without consulting inspection
        // or verifying the surviving pair; older membership obligations remain retained.
        let policy = self.publication_policy.as_deref().or_else(|| {
            self.cfg
                .takedown_denial
                .then_some(&clearance::Immediate as &dyn clearance::PublicationPolicy)
        });
        #[cfg(feature = "remote-hooks")]
        let policy = policy.or_else(|| {
            (!self.inspectors.is_empty())
                .then_some(&inspection::Immediate as &dyn clearance::PublicationPolicy)
        });
        // Pair coverage is required exactly when a policy regime exists and no
        // written ref is deleted; the gate stays identical to the previous
        // policy.is_some() && all-new condition.
        let requirement = mkit_primitives::closure::pair::pair_requirement(
            mkit_primitives::closure::pair::PairConfig {
                #[cfg(feature = "remote-hooks")]
                inspectors: !self.inspectors.is_empty(),
                #[cfg(not(feature = "remote-hooks"))]
                inspectors: false,
                takedown: self.cfg.takedown_denial,
                custom_policy: self.publication_policy.is_some(),
            },
            if req.refs.iter().all(|update| update.new.is_some()) {
                mkit_primitives::closure::pair::PairWrite::Advance
            } else {
                mkit_primitives::closure::pair::PairWrite::Deletion
            },
        );
        debug_assert_eq!(
            matches!(
                requirement,
                mkit_primitives::closure::pair::PairRequirement::Required
            ),
            policy.is_some() && req.refs.iter().all(|update| update.new.is_some()),
            "pair requirement must agree with the existing policy gate"
        );
        if let Some(policy) = policy
            && !req.refs.is_empty()
            && matches!(
                requirement,
                mkit_primitives::closure::pair::PairRequirement::Required
            )
        {
            let snapshot = ahead.get_or_insert_with(Snapshot::default);
            let settlement = crate::indexed::budget::Budgeted::new(&self.meta, budget.root());
            publication_budget::PublicationBudget::settle(
                budget.root(),
                self.fill_with(&settlement, p, snapshot, req.read_keys())
                    .await,
            )?;
            let pair = clearance::resulting_pair(&op.repo.name, req.refs, snapshot)?;
            let mut prepared = policy.prepare(op, &pair).await?;
            if prepared.value != pair {
                return Err(internal("publication policy changed the resulting pair"));
            }
            // Membership dependencies belong to the server, not to an
            // inspector's verdict. An Inspect Pass alone cannot publish.
            let row =
                crate::store::publication::Publication::decode(snapshot.get(&keys::publication(
                    &op.repo.name,
                    &crate::store::publication::sequence_ref(&req.refs[0].name),
                )))
                .map_err(meta_error)?;
            prepared.generation = row.generation;
            // The proof below is only valid for this exact publication row.
            let bound = clearance::PreparedAt::of(&row);
            prepared.additions = if let Some(advance) = &req.advance {
                advance
                    .ids
                    .iter()
                    .map(|id| {
                        snapshot
                            .get(&keys::ticket(id))
                            .ok_or_else(|| internal("publication ticket missing"))
                            .and_then(|raw| {
                                codec::decode_ticket(raw)
                                    .map(|t| t.pack_id)
                                    .map_err(meta_error)
                            })
                    })
                    .collect::<Result<Vec<_>, _>>()?
            } else {
                implicit_ids.map(<[Hash]>::to_vec).unwrap_or_default()
            };
            #[cfg(feature = "remote-hooks")]
            let mut inspected = inspected;
            #[cfg(feature = "remote-hooks")]
            let verification_set = inspected.as_deref_mut();
            #[cfg(not(feature = "remote-hooks"))]
            let verification_set = inspected;
            self.verify_publication(
                op,
                p,
                &mut prepared,
                policy,
                mkit_attest::grant::head_packmap(&crate::store::publication::sequence_ref(
                    &req.refs[0].name,
                ))
                .is_some(),
                external_bases,
                verification_set,
                req.advance
                    .as_ref()
                    .and_then(|a| {
                        a.ids
                            .iter()
                            .filter_map(|id| {
                                snapshot
                                    .get(&keys::ticket(id))
                                    .and_then(|raw| codec::decode_ticket(raw).ok())
                                    .filter(|t| Some(t.pack_id) == pair.packmap)
                                    .map(|t| t.created_at_ms)
                            })
                            .min()
                    })
                    .unwrap_or_else(|| {
                        op.auth
                            .as_ref()
                            .map_or(ms(self.clock.now_ms()), |a| ms(a.created_at_ms))
                    }),
                budget,
            )
            .await?;
            #[cfg(feature = "remote-hooks")]
            if let Some(set) = inspected {
                let assignment = if self.cfg.scanner_retrieval.is_some() {
                    Some(Self::retrieval_assignment(
                        op,
                        req.advance.as_ref(),
                        repository,
                        snapshot,
                        set,
                    )?)
                } else {
                    None
                };
                self.inspect_advance(
                    op,
                    &prepared.value,
                    set.clone().finalize(),
                    assignment.as_ref(),
                )
                .await?;
            }
            Ok(Some((prepared, bound)))
        } else {
            Ok(None)
        }
    }

    #[allow(clippy::too_many_arguments, clippy::too_many_lines)] // Carry consuming-ticket age for repository lag classification.
    async fn verify_publication(
        &self,
        op: &Operation,
        p: &Partition,
        prepared: &mut crate::store::publication::Advance,
        policy: &dyn clearance::PublicationPolicy,
        branch: bool,
        external_bases: &std::collections::BTreeSet<Hash>,
        mut inspected: Option<&mut crate::indexed::inspection::InspectionSet>,
        created: u64,
        budget: &publication_budget::PublicationBudget,
    ) -> Result<(), ServerError> {
        let indexed = self
            .cfg
            .indexed
            .ok_or_else(|| internal("publication requires indexed mode"))?;
        let resumed = self.cfg.takedown_denial
            && self.publication_policy.is_none()
            && inspected.is_none()
            && publication_budget::PublicationBudget::settle(
                budget.root(),
                Box::pin(crate::indexed::publication::resume::prepare_with(
                    &self.meta,
                    p,
                    self.shards.as_ref(),
                    &op.repo,
                    prepared,
                    indexed,
                    ms(self.clock.now_ms()),
                    self.metrics.as_ref(),
                    created,
                    branch,
                    Some(budget.proof()),
                    Some(budget.root()),
                ))
                .await,
            )?;
        // The canonical fallback retains delta bases; only the metadata-only
        // continuation can use the whole-job allowance without that residency.
        let mut indexed = indexed;
        if self.cfg.takedown_denial && !resumed {
            indexed.decode_budget = indexed.decode_budget.min(8 << 20);
        }
        // Pair verification and the inspection metadata share one slice of the
        // request's ledger; dependency visibility draws from the ledger itself.
        let slice = budget.verify_slice();
        let lag = crate::indexed::publication::Lag {
            now: ms(self.clock.now_ms()),
            created,
            bound: indexed.relay_lag_bound_ms,
        };
        let denial_reads = crate::store::DenialReads::new(&self.meta, self.cfg.takedown_denial);
        if let Some(set) = inspected.as_deref_mut() {
            crate::indexed::publication::verify_inspected_within(
                &self.blobs,
                &denial_reads,
                self.shards.as_ref(),
                &op.repo,
                &prepared.value.clone(),
                branch,
                prepared,
                policy,
                indexed,
                self.metrics.as_ref(),
                self.cfg.takedown_denial,
                set,
                lag,
                &slice,
            )
            .await?;
        } else if !resumed {
            crate::indexed::publication::verify_within(
                &self.blobs,
                &denial_reads,
                self.shards.as_ref(),
                &op.repo,
                &prepared.value.clone(),
                branch,
                prepared,
                policy,
                indexed,
                self.metrics.as_ref(),
                self.cfg.takedown_denial,
                lag,
                &slice,
            )
            .await?;
        }
        prepared.external_bases = prepared
            .external_bases
            .iter()
            .copied()
            .chain(external_bases.iter().copied())
            .collect::<std::collections::BTreeSet<_>>()
            .into_iter()
            .collect();
        if prepared.external_bases.len() > crate::store::publication::MAX_ADVANCE_ITEMS {
            return Err(publication_budget::PublicationBudget::capacity_error());
        }
        if prepared.state.publishable() {
            // Inspection keeps its one shared slice; otherwise dependencies
            // draw from the request ledger directly.
            let dependency_budget = if inspected.is_some() {
                &slice
            } else {
                budget.proof()
            };
            let meta = crate::indexed::budget::Budgeted::new(&self.meta, dependency_budget);
            let visible = publication_budget::PublicationBudget::settle(
                dependency_budget,
                crate::timers::publication_recheck::dependencies(
                    &meta,
                    &meta,
                    p,
                    self.shards.as_ref(),
                    &op.repo,
                    prepared,
                )
                .await
                .map_err(meta_error),
            )?;
            if !visible {
                prepared.state = crate::store::publication::Clearance::Pending;
            }
        }
        Ok(())
    }

    /// [`Self::apply_loop`] on a store with atomic multi-key batches, which
    /// replay records and quota need.
    async fn apply_atomic(
        &self,
        op: &Operation,
        a: &Authenticated,
        p: &Partition,
        req: &WriteRequest<'_>,
        ahead: Option<Snapshot>,
        budget: (
            Option<&publication_budget::PublicationBudget>,
            &ReplacedSession,
        ),
    ) -> Result<StoredResult, ServerError> {
        if !self.meta.capabilities().atomic_multi_key {
            return Err(internal("replay and quota need atomic multi-key batches"));
        }
        self.apply_loop(op, a, p, req, ahead, budget).await
    }

    /// The bounded optimistic loop: read, plan, apply. The first attempt
    /// retains read-ahead only when no global denial proof is required.
    /// Each attempt fixes its plan time before proof; fresh rows, a usable
    /// lease and current business time follow it. A guard another
    /// writer broke re-plans up to [`MAX_REPLAN`] times, then `aborted`; a
    /// lost prune race retries once without the prune, uncounted. A missed
    /// deadline re-plans once while the envelope is still valid at the
    /// failed commit, then `unavailable` (SPEC-WRITE-GRANTS §5.5).
    // Keep fresh denial, authorization and guarded apply together on every retry.
    #[allow(clippy::too_many_lines)]
    async fn apply_loop(
        &self,
        op: &Operation,
        a: &Authenticated,
        p: &Partition,
        req: &WriteRequest<'_>,
        mut ahead: Option<Snapshot>,
        (budget, replaced): (
            Option<&publication_budget::PublicationBudget>,
            &ReplacedSession,
        ),
    ) -> Result<StoredResult, ServerError> {
        let mut req = req.for_store(self.meta.capabilities());
        // Held until the loop ends (see `with_write_gate`).
        let _gate = match &self.gate {
            Some(gate) => Some(gate.enter(p).await),
            None => None,
        };
        let skew_ms = a.business_skew_ms;
        let (mut replans, mut deadline_missed, mut prune_ok) = (0, false, true);
        let mut first_attempt = true;
        // Every attempt, including CAS replans, draws from the request's one
        // ledger. Only a write with no publication proof owns a fresh allowance.
        let own_budget;
        let denial_budget = if let Some(budget) = budget {
            budget.proof()
        } else {
            own_budget = crate::indexed::budget::SliceBudget::new(crate::limits::REQUEST_CALLS);
            &own_budget
        };
        // Settlement calls (snapshot, lease, commit) charge the request root, or
        // nothing when the write carries no publication ledger.
        let ledger = budget.map(publication_budget::PublicationBudget::root);
        let meter = publication_budget::PublicationBudget::meter(ledger);
        let settlement = &meter;
        loop {
            let denial_packs: Vec<_> = req
                .denial_packs
                .iter()
                .chain(
                    req.publication
                        .iter()
                        .filter_map(|p| p.prepared)
                        .flat_map(|a| a.dependencies.iter().chain(&a.external_bases)),
                )
                .copied()
                .collect();
            let prove = self.cfg.takedown_denial
                && req
                    .denial_ids
                    .is_some_and(|ids| !ids.is_empty() || !denial_packs.is_empty());
            // Every gating denial read is at/after this attempt's plan time
            // (SPEC-SERVER §14.2). Slow proof cannot borrow a new commit window.
            let proof_plan_time = prove.then(|| ms(self.clock.now_ms()));
            if let Some(ids) = req.denial_ids.filter(|_| prove) {
                publication_budget::PublicationBudget::settle(
                    denial_budget,
                    crate::takedown::denial::require_repo_clear_budgeted(
                        &self.meta,
                        self.shards.as_ref(),
                        &op.repo,
                        ids,
                        &denial_packs,
                        denial_budget,
                    )
                    .await,
                )?;
            }
            // A complete proof can outlive both the commit window and the
            // initial lease. Only fixed admission quota facts survive it;
            // every mutable source row is read again before planning.
            let base = ahead.take().unwrap_or_default();
            let base = if prove {
                let mut fresh = Snapshot::default();
                fresh.namespace_window = base.namespace_window;
                fresh.namespace_seed = base.namespace_seed;
                fresh
            } else {
                base
            };
            let clock = self.plan_clock(skew_ms, &req);
            let snap = publication_budget::PublicationBudget::settle(
                settlement,
                self.read_snapshot(p, &req, &clock, base, prune_ok, ledger)
                    .await,
            )?;
            if let Some(lease) = req.lease
                && (prove
                    || !first_attempt
                    || lease
                        .value
                        .expires_at_ms
                        .saturating_sub(self.cfg.lease_margin_ms)
                        < ms(self.clock.now_ms()).saturating_add(self.cfg.min_lease_budget_ms))
            {
                let (_, renewed) = publication_budget::PublicationBudget::settle(
                    settlement,
                    async {
                        let observed = self.observe_lease(op, p, Some(&snap), ledger).await?;
                        self.admit_lease(op, p, observed, skew_ms, ledger).await
                    }
                    .await,
                )?;
                req.lease = Some(renewed);
            }
            first_attempt = false;
            let mut clock = self.plan_clock(skew_ms, &req);
            if let Some(plan_time) = proof_plan_time {
                // Keep fresh business time and current lease/replay caps; only
                // the denial attempt's original plan time remains immutable.
                clock.plan_time_ms = plan_time;
            }
            let plan = match plan_write(&req, &snap, &clock)? {
                Planned::Done(result) => return Ok(result),
                Planned::Apply(plan) => plan,
            };
            let Plan {
                batch,
                on_commit,
                replay_index,
                epoch_index,
                pending_index,
                prune,
                prune_from,
            } = plan;
            require_relay_source_lease(self.cfg.sharding, req.lease.is_some(), &batch)?;
            #[cfg(feature = "__test-faults")]
            let batch = faults::delay_relay_batch(
                batch,
                a.test_directives(),
                op,
                ms(clock.business_now_ms),
            );
            if req.kind != WriteKind::UploadReserve {
                #[cfg(feature = "__test-faults")]
                {
                    let mut attempt = op.clone();
                    attempt.leased_epoch = req.lease.map(|l| l.value.epoch);
                    fault!(self, BeforeFinalApply, &attempt, a);
                }
            }
            tracing::debug!(stage = "apply", replans);
            if req.rejection.is_none() && op.published_source.is_some() {
                let source_store = crate::indexed::budget::Budgeted::new(&self.meta, &meter);
                publication_budget::PublicationBudget::settle(
                    settlement,
                    self.fence_published_source(op, a, &source_store).await,
                )?;
            }
            let applied = crate::indexed::budget::Budgeted::new(&self.meta, &meter)
                .apply(p, batch)
                .await;
            match applied {
                Ok(BatchOutcome::Committed) => {
                    if matches!(
                        on_commit,
                        StoredResult::AdvanceRefs(AdvanceOutcome::Committed)
                    ) && let OpKind::AdvanceRefs { tickets, .. } = &op.kind
                    {
                        for ticket in tickets {
                            crate::telemetry::verification_progress(
                                self.metrics.as_ref(),
                                "final_cas",
                                ms(self.clock.now_ms()),
                                Some(ticket),
                                None,
                            );
                        }
                    }
                    #[cfg(feature = "__test-faults")]
                    self.schedule_test_ref_timer(op, a, &on_commit, ms(clock.business_now_ms))
                        .await?;
                    if let Some(begin) = req.begin
                        && let Some((key, session)) =
                            begin::replaced_session(begin, &snap, ms(clock.business_now_ms))
                    {
                        *replaced
                            .lock()
                            .unwrap_or_else(std::sync::PoisonError::into_inner) =
                            Some((key.into(), session));
                    }
                    return Ok(on_commit);
                }
                Ok(BatchOutcome::DeadlinePassed { backend_now }) => {
                    tracing::info!(
                        backend_now,
                        deadline = clock.deadline(),
                        "commit deadline passed"
                    );
                    // Validity at the failed commit, on both clocks.
                    let now = self.clock.now_ms().saturating_add(skew_ms);
                    let backend = i64::try_from(backend_now).unwrap_or(i64::MAX);
                    let valid = req
                        .replay
                        .is_none_or(|r| now.max(backend) <= r.expires_at_ms);
                    if deadline_missed || !valid {
                        return Err(ServerError::unavailable("commit deadline passed; retry"));
                    }
                    deadline_missed = true;
                }
                Ok(BatchOutcome::PreconditionFailed { index, observed }) => {
                    if Some(index) == pending_index {
                        return Err(ServerError::unavailable(
                            "admission reservation changed; retry",
                        ));
                    }
                    if Some(index) == replay_index {
                        return replay_raced(&req, observed.as_ref());
                    }
                    if Some(index) == epoch_index {
                        return Err(plan::epoch_moved());
                    }
                    if index >= prune_from && prune_ok {
                        prune_ok = false;
                        continue;
                    }
                    replans += 1;
                    if replans > MAX_REPLAN {
                        return Err(ServerError::aborted_retryable("write contention; retry")
                            .with_abort_cause(AbortCause::Contention));
                    }
                }
                Err(StoreError::Full) => return Err(self.partition_full(p, prune).await),
                Err(e) => {
                    return publication_budget::PublicationBudget::settle(
                        settlement,
                        Err(meta_error(e)),
                    );
                }
            }
        }
    }

    #[cfg(feature = "__test-faults")]
    async fn schedule_test_ref_timer(
        &self,
        op: &Operation,
        a: &Authenticated,
        on_commit: &StoredResult,
        now_ms: u64,
    ) -> Result<(), ServerError> {
        if let OpKind::UpdateRef(upd) = &op.kind
            && matches!(
                on_commit,
                StoredResult::UpdateRef(UpdateRefResult::Committed)
            )
        {
            let timer_partition = self.shards.ref_shard(&op.repo, &upd.name);
            faults::schedule_timer(
                a.test_directives(),
                &self.meta,
                &timer_partition,
                &op.repo.name,
                &upd.name,
                now_ms,
            )
            .await?;
        }
        Ok(())
    }

    /// The deadline uses the injected clock unshifted; business time adds
    /// the request's skew. A signed write's deadline is also capped at
    /// `expires_at + MAX_CLOCK_LEAD_MS`, below the replay prune grace.
    fn plan_clock(&self, skew_ms: i64, req: &WriteRequest<'_>) -> PlanClock {
        let now = self.clock.now_ms();
        let lead = MAX_CLOCK_LEAD_MS.unsigned_abs();
        PlanClock {
            plan_time_ms: ms(now),
            business_now_ms: now.saturating_add(skew_ms),
            max_apply_window_ms: u64::try_from(self.cfg.max_apply_window.as_millis())
                .unwrap_or(u64::MAX),
            deadline_cap: match (
                req.replay.map(|r| ms(r.expires_at_ms).saturating_add(lead)),
                req.lease.map(|l| {
                    l.value
                        .expires_at_ms
                        .saturating_sub(self.cfg.lease_margin_ms)
                }),
            ) {
                (Some(replay), Some(lease)) => Some(replay.min(lease)),
                (replay, lease) => replay.or(lease),
            },
        }
    }

    /// Everything [`plan_write`] reads that `base` lacks, in one
    /// `get_many`. A sampled write ([`prune_sampled`]) first scans a
    /// bounded page of prune candidates, on the real clock, never the
    /// business clock.
    async fn read_snapshot(
        &self,
        p: &Partition,
        req: &WriteRequest<'_>,
        clock: &PlanClock,
        mut snap: Snapshot,
        prune: bool,
        ledger: Option<&crate::indexed::budget::SliceBudget>,
    ) -> Result<Snapshot, ServerError> {
        let now = clock.plan_time_ms;
        let meter = publication_budget::PublicationBudget::meter(ledger);
        let meta = crate::indexed::budget::Budgeted::new(&self.meta, &meter);
        if prune && prune_sampled(req, now) {
            if req.replay.is_some() {
                snap.expired_replays = read::expired_replay_keys(&meta, p, now, PRUNE_LIMIT)
                    .await
                    .map_err(meta_error)?;
            }
            if let Some(window) = req.charges.iter().map(|c| c.limits.window_ms).max() {
                snap.stale_quotas = read::stale_quota_keys(&meta, p, now, ms(window), PRUNE_LIMIT)
                    .await
                    .map_err(meta_error)?;
            }
        }
        let mut wanted = req.read_keys();
        wanted.extend(snap.stale_quotas.iter().map(|(_, quota)| quota.clone()));
        self.fill_with(&meta, p, &mut snap, wanted).await?;
        if let Some(advance) = &req.advance {
            let detail = advance::detail_keys(&snap, advance)?;
            self.fill_with(&meta, p, &mut snap, detail).await?;
        }
        if let Some(BeginWrite::Open(open)) = req.begin {
            begin::read_indexed(&meta, p, &open.spec, &mut snap).await?;
            let reservation = crate::store::tickets::keys(&open.spec).reservation;
            if snap.get(&reservation).is_some()
                && let Some(replay) = req.replay
            {
                let key = keys::replay(&replay.scope);
                let value = meta.get(p, &key).await.map_err(meta_error)?;
                snap.insert(key, value);
            }
        }
        Ok(snap)
    }

    /// Apply a batch, typing a full partition as retryable `unavailable`.
    async fn apply_meta(&self, p: &Partition, batch: Batch) -> Result<BatchOutcome, ServerError> {
        match self.meta.apply(p, batch).await {
            Ok(outcome) => Ok(outcome),
            Err(StoreError::Full) => Err(self.partition_full(p, None).await),
            Err(error) => Err(meta_error(error)),
        }
    }

    /// Fork helpers collapse storage failures. A full partition stays the
    /// shared capacity failure, including its counter.
    async fn fork_storage_error(
        &self,
        p: &Partition,
        error: crate::fork::ForkError,
    ) -> ServerError {
        if error.is_partition_full() {
            self.partition_full(p, None).await
        } else {
            error.error()
        }
    }

    /// A full partition: count it, retry the prune alone (deletes still
    /// work) and fail closed with a retryable `unavailable`.
    async fn partition_full(&self, p: &Partition, prune: Option<Batch>) -> ServerError {
        self.metrics
            .incr(METRIC_PARTITION_FULL, &[("kind", p.kind())], 1);
        let name = p.encode().map(|b| to_hex_bytes(&b)).unwrap_or_default();
        tracing::error!(partition = %name, kind = p.kind(), "storage partition full");
        if let Some(prune) = prune
            && let Err(e) = self.meta.apply(p, prune).await
        {
            tracing::warn!(error = %e, "prune on a full partition failed");
        }
        ServerError::unavailable("storage partition full")
    }
}

/// The operation a write's reservation records.
fn stored_procedure(kind: &OpKind) -> Result<codec::StoredProcedure, ServerError> {
    Ok(match kind {
        OpKind::UpdateRef(_) => codec::StoredProcedure::UpdateRef,
        OpKind::AdvanceRefs { .. } => codec::StoredProcedure::AdvanceRefs,
        OpKind::BeginUpload { .. } => codec::StoredProcedure::BeginUpload,
        OpKind::UploadPack { .. } => codec::StoredProcedure::UploadPack,
        OpKind::SetRepoVisibility { visibility } => {
            codec::StoredProcedure::SetRepoVisibility(stored_visibility(*visibility))
        }
        _ => return Err(internal("a read operation cannot hold a write reservation")),
    })
}

/// The allowance stays local until the guarded apply.
#[derive(Default)]
struct Allowance {
    charges: Vec<QuotaCharge>,
    reservation: Option<String>,
    response_headers: Vec<(String, String)>,
    external_ref: Option<String>,
}

/// A ref name the pipeline reads or writes: at most
/// [`refs::MAX_REF_NAME_BYTES`], the SPEC-REFS §3 grammar, and under
/// `refs/` ([`refs::is_served_ref_name`], R-86), each refused by name.
fn check_ref_name(name: &str) -> Result<(), ServerError> {
    if name.len() > refs::MAX_REF_NAME_BYTES {
        Err(ServerError::invalid_argument(refs::REF_NAME_TOO_LONG))
    } else if !validate_ref_name(name) {
        Err(ServerError::invalid_argument(
            "ref name is invalid (SPEC-REFS §3)",
        ))
    } else if refs::is_served_ref_name(name) {
        Ok(())
    } else {
        Err(ServerError::invalid_argument(refs::REF_NAME_OUTSIDE_REFS))
    }
}

/// A result of another procedure: a stored rejection is its error; any
/// other kind is corruption (the fingerprint covers the procedure).
fn stored_mismatch(result: &StoredResult) -> ServerError {
    match result {
        StoredResult::Rejected(rejection) => {
            ServerError::new(rejection.code(), rejection.message().to_owned())
        }
        _ => internal("stored result is for another procedure"),
    }
}

/// The replay guard failed: another request with this nonce committed
/// first. Classify its record like stage 0 does.
fn replay_raced(
    req: &WriteRequest<'_>,
    observed: Option<&Value>,
) -> Result<StoredResult, ServerError> {
    // Receipts and a Committed outcome belong to this request only (brief
    // B7): a same-nonce loser holding its own reservation aborts it, whatever
    // the winner stored.
    if req.pending.is_some() {
        return Err(
            ServerError::aborted_retryable("operation already in flight; retry")
                .with_abort_cause(AbortCause::ReplayRace),
        );
    }
    let (Some(replay), Some(value)) = (req.replay, observed) else {
        return Err(ServerError::aborted_retryable(
            "operation already in flight; retry",
        ));
    };
    let record = codec::decode_replay_record(value).map_err(meta_error)?;
    replay_answer(classify(Some(&record), &replay.fingerprint))?
        .ok_or_else(|| ServerError::aborted_retryable("operation already in flight; retry"))
}

Files