rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

state_host.rs (20536B)


      1 //! Sealed lifecycle boundary for the canonical RHI SQLite state catalog.
      2 
      3 use core::fmt;
      4 use std::{error::Error, path::Path};
      5 
      6 use radroots_service_sqlite::{
      7     BackupCreatedAtUnixMs, ExistingServiceDatabaseIntent, IntegrityCheckedAtUnixMs,
      8     MigrationAppliedAtUnixSeconds, MigrationBuildIdentity, OpenMode, ServiceBackupManifest,
      9     ServiceSqliteApplicationId, ServiceSqliteConnectionOptions, ServiceSqliteHost,
     10     ServiceSqliteInitializer, ServiceSqliteInitializerFuture, ServiceSqliteIntegrityReport,
     11     ServiceSqlitePaths, initialize_database,
     12 };
     13 
     14 use crate::{
     15     RHI_STATE_APPLICATION_ID, RHI_STATE_BASE_SCHEMA_VERSION, RHI_STATE_SCHEMA_VERSION,
     16     RhiConfigApplyError, RhiConfigApplyErrorKind, RhiConfigApplyOutcome, RhiConfigDocumentV1,
     17     RhiRuntimeContext, RhiStateMaintenanceError, RhiStateMaintenanceErrorKind, RhiStateMetadata,
     18     RhiStateRepositories, rhi_migration_catalog, rhi_schema_catalog, state_config,
     19     validate_rhi_state_catalogs,
     20 };
     21 
     22 /// Stable lifecycle mode of one opened RHI state host.
     23 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
     24 pub enum RhiStateHostMode {
     25     ReadWriteExisting,
     26     ReadOnlyInspection,
     27 }
     28 
     29 /// Stable source-free class for an RHI state-host lifecycle failure.
     30 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
     31 pub enum RhiStateHostErrorKind {
     32     InvalidPaths,
     33     InvalidEvidence,
     34     Catalog,
     35     Initialize,
     36     ReadWriteOpen,
     37     InspectionOpen,
     38     Close,
     39 }
     40 
     41 impl RhiStateHostErrorKind {
     42     /// Returns the stable machine-readable failure code.
     43     #[must_use]
     44     pub const fn code(self) -> &'static str {
     45         match self {
     46             Self::InvalidPaths => "state_paths_invalid",
     47             Self::InvalidEvidence => "state_evidence_invalid",
     48             Self::Catalog => "state_catalog_invalid",
     49             Self::Initialize => "state_initialize_failed",
     50             Self::ReadWriteOpen => "state_read_write_open_failed",
     51             Self::InspectionOpen => "state_inspection_open_failed",
     52             Self::Close => "state_close_failed",
     53         }
     54     }
     55 }
     56 
     57 /// Redacted RHI state-host lifecycle failure.
     58 #[derive(Clone, Copy, PartialEq, Eq)]
     59 pub struct RhiStateHostError {
     60     kind: RhiStateHostErrorKind,
     61 }
     62 
     63 impl RhiStateHostError {
     64     const fn new(kind: RhiStateHostErrorKind) -> Self {
     65         Self { kind }
     66     }
     67 
     68     /// Returns the stable failure class.
     69     #[must_use]
     70     pub const fn kind(self) -> RhiStateHostErrorKind {
     71         self.kind
     72     }
     73 
     74     /// Returns the stable machine-readable failure code.
     75     #[must_use]
     76     pub const fn code(self) -> &'static str {
     77         self.kind.code()
     78     }
     79 }
     80 
     81 impl fmt::Display for RhiStateHostError {
     82     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     83         formatter.write_str(match self.kind {
     84             RhiStateHostErrorKind::InvalidPaths => "RHI state paths are invalid",
     85             RhiStateHostErrorKind::InvalidEvidence => "RHI state identity evidence is invalid",
     86             RhiStateHostErrorKind::Catalog => "RHI state catalogs are invalid",
     87             RhiStateHostErrorKind::Initialize => "RHI state initialization failed",
     88             RhiStateHostErrorKind::ReadWriteOpen => "RHI writable state could not be opened",
     89             RhiStateHostErrorKind::InspectionOpen => "RHI inspection state could not be opened",
     90             RhiStateHostErrorKind::Close => "RHI state host could not be closed",
     91         })
     92     }
     93 }
     94 
     95 impl fmt::Debug for RhiStateHostError {
     96     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     97         formatter
     98             .debug_struct("RhiStateHostError")
     99             .field("kind", &self.kind)
    100             .finish()
    101     }
    102 }
    103 
    104 impl Error for RhiStateHostError {}
    105 
    106 /// One opened RHI state catalog whose raw SQLite authority remains sealed.
    107 ///
    108 /// Callers cannot construct the wrapper or extract the shared host:
    109 ///
    110 /// ```compile_fail
    111 /// use rhi::{RhiStateHost, RhiStateHostMode};
    112 ///
    113 /// let _ = RhiStateHost {
    114 ///     host: todo!(),
    115 ///     mode: RhiStateHostMode::ReadWriteExisting,
    116 /// };
    117 /// ```
    118 ///
    119 /// The wrapper intentionally exposes no transaction or connection escape:
    120 ///
    121 /// ```compile_fail
    122 /// use rhi::RhiStateHost;
    123 ///
    124 /// fn bypass(host: &RhiStateHost) {
    125 ///     let _ = host.transaction(|_| async { Ok::<_, ()>(()) });
    126 /// }
    127 /// ```
    128 pub struct RhiStateHost {
    129     host: ServiceSqliteHost,
    130     mode: RhiStateHostMode,
    131     metadata: RhiStateMetadata,
    132 }
    133 
    134 impl RhiStateHost {
    135     pub(crate) const fn sqlite_host(&self) -> &ServiceSqliteHost {
    136         &self.host
    137     }
    138     /// Returns the lifecycle mode selected when this host was opened.
    139     #[must_use]
    140     pub const fn mode(&self) -> RhiStateHostMode {
    141         self.mode
    142     }
    143 
    144     /// Returns the immutable RHI metadata bound to this host session.
    145     #[must_use]
    146     pub const fn metadata(&self) -> &RhiStateMetadata {
    147         &self.metadata
    148     }
    149 
    150     /// Returns the sealed family of typed repository capabilities.
    151     #[must_use]
    152     pub const fn repositories(&self) -> RhiStateRepositories<'_> {
    153         RhiStateRepositories::new(self)
    154     }
    155 
    156     /// Captures one governed point-in-time backup from a writable RHI host.
    157     ///
    158     /// The staging directory must be a new absolute path. The returned
    159     /// manifest remains in memory and contains no protected identity material.
    160     pub async fn capture_online_backup(
    161         &self,
    162         staging_directory: &Path,
    163         created_at: BackupCreatedAtUnixMs,
    164     ) -> Result<ServiceBackupManifest, RhiStateMaintenanceError> {
    165         if self.mode != RhiStateHostMode::ReadWriteExisting {
    166             return Err(RhiStateMaintenanceError::new(
    167                 RhiStateMaintenanceErrorKind::InvalidMode,
    168             ));
    169         }
    170         self.host
    171             .capture_online_backup(staging_directory, created_at)
    172             .await
    173             .map_err(RhiStateMaintenanceError::from_sqlite)
    174     }
    175 
    176     /// Runs one explicit bounded integrity inspection over this host.
    177     pub async fn inspect_integrity(
    178         &self,
    179         checked_at: IntegrityCheckedAtUnixMs,
    180     ) -> Result<ServiceSqliteIntegrityReport, RhiStateMaintenanceError> {
    181         self.host
    182             .inspect_integrity(checked_at)
    183             .await
    184             .map_err(RhiStateMaintenanceError::from_sqlite)
    185     }
    186 
    187     /// Drains the shared host and explicitly releases retained authority.
    188     pub async fn close(&self) -> Result<(), RhiStateHostError> {
    189         self.host
    190             .close()
    191             .await
    192             .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Close))
    193     }
    194 }
    195 
    196 impl fmt::Debug for RhiStateHost {
    197     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
    198         formatter
    199             .debug_struct("RhiStateHost")
    200             .field("mode", &self.mode)
    201             .field("state", &"[sealed]")
    202             .finish()
    203     }
    204 }
    205 
    206 /// Creates a missing RHI catalog exactly once and releases initialization authority.
    207 ///
    208 /// This function never opens an existing database as initialization. The caller
    209 /// injects the shared metadata and migration evidence. Contract versions are
    210 /// cross-bound before database I/O, and all governed migrations are applied by
    211 /// the shared host before initialization authority is explicitly released.
    212 pub async fn initialize_rhi_state(
    213     runtime: &RhiRuntimeContext,
    214     metadata: &RhiStateMetadata,
    215     applied_at: MigrationAppliedAtUnixSeconds,
    216     build: &MigrationBuildIdentity,
    217 ) -> Result<(), RhiStateHostError> {
    218     let paths = state_paths(runtime)?;
    219     require_metadata(runtime, metadata)?;
    220     require_migration_build(metadata, build)?;
    221     let (migrations, schema) = catalogs()?;
    222     provision_state_directory(runtime)?;
    223     let authority = initialize_database(
    224         &paths,
    225         OpenMode::Initialize,
    226         metadata.initial_database_metadata(),
    227         &schema,
    228         initialize_empty_catalog,
    229     )
    230     .await
    231     .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Initialize))?;
    232     let identity = metadata.database_identity();
    233     let (host, outcome) = ServiceSqliteHost::open_initialized(
    234         &paths,
    235         &identity,
    236         &migrations,
    237         &schema,
    238         ServiceSqliteConnectionOptions::reviewed(),
    239         authority,
    240         applied_at,
    241         build,
    242         &[],
    243     )
    244     .await
    245     .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Initialize))?;
    246     if !exact_migration_outcome(outcome) {
    247         return Err(close_error(&host, RhiStateHostErrorKind::Catalog).await);
    248     }
    249     let state = RhiStateHost {
    250         host,
    251         mode: RhiStateHostMode::ReadWriteExisting,
    252         metadata: metadata.clone(),
    253     };
    254     if state_config::bind_or_verify(&state, metadata, applied_at, build)
    255         .await
    256         .is_err()
    257     {
    258         return Err(close_error(&state.host, RhiStateHostErrorKind::Initialize).await);
    259     }
    260     state
    261         .close()
    262         .await
    263         .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Initialize))
    264 }
    265 
    266 /// Opens an already initialized RHI catalog with exclusive writer authority.
    267 ///
    268 /// Missing state is never created. Migration time and build identity remain
    269 /// explicit injected evidence for every governed migration or exact-current
    270 /// reopen.
    271 pub async fn open_rhi_state_read_write(
    272     runtime: &RhiRuntimeContext,
    273     metadata: &RhiStateMetadata,
    274     applied_at: MigrationAppliedAtUnixSeconds,
    275     build: &MigrationBuildIdentity,
    276 ) -> Result<RhiStateHost, RhiStateHostError> {
    277     let paths = state_paths(runtime)?;
    278     require_metadata(runtime, metadata)?;
    279     require_migration_build(metadata, build)?;
    280     let identity = metadata.database_identity();
    281     let (migrations, schema) = catalogs()?;
    282     let (host, outcome) = ServiceSqliteHost::open_read_write_existing(
    283         &paths,
    284         &identity,
    285         &migrations,
    286         &schema,
    287         ServiceSqliteConnectionOptions::reviewed(),
    288         applied_at,
    289         build,
    290         &[],
    291     )
    292     .await
    293     .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::ReadWriteOpen))?;
    294     if !exact_migration_outcome(outcome) {
    295         return Err(close_error(&host, RhiStateHostErrorKind::Catalog).await);
    296     }
    297     let state = RhiStateHost {
    298         host,
    299         mode: RhiStateHostMode::ReadWriteExisting,
    300         metadata: metadata.clone(),
    301     };
    302     if state_config::bind_or_verify(&state, metadata, applied_at, build)
    303         .await
    304         .is_err()
    305     {
    306         return Err(close_error(&state.host, RhiStateHostErrorKind::InvalidEvidence).await);
    307     }
    308     Ok(state)
    309 }
    310 
    311 /// Opens existing RHI state from configuration intent and discovers source identity.
    312 ///
    313 /// Missing state is never created. Source generation and database creation time
    314 /// are read under the same retained writer authority returned in the host.
    315 pub async fn open_rhi_state_read_write_from_config(
    316     runtime: &RhiRuntimeContext,
    317     configuration: &RhiConfigDocumentV1,
    318     applied_at: MigrationAppliedAtUnixSeconds,
    319     build: &MigrationBuildIdentity,
    320 ) -> Result<RhiStateHost, RhiStateHostError> {
    321     let paths = state_paths(runtime)?;
    322     let intent = existing_intent(&paths)?;
    323     let (migrations, schema) = catalogs()?;
    324     let (opened, outcome) = ServiceSqliteHost::open_read_write_existing_with_intent(
    325         &paths,
    326         &intent,
    327         &migrations,
    328         &schema,
    329         ServiceSqliteConnectionOptions::reviewed(),
    330         applied_at,
    331         build,
    332         &[],
    333     )
    334     .await
    335     .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::ReadWriteOpen))?;
    336     if !exact_migration_outcome(outcome) {
    337         let (host, _) = opened.into_parts();
    338         return Err(close_error(&host, RhiStateHostErrorKind::Catalog).await);
    339     }
    340     let (host, actual) = opened.into_parts();
    341     let metadata = match RhiStateMetadata::from_existing_database(runtime, configuration, &actual) {
    342         Ok(metadata) => metadata,
    343         Err(_) => {
    344             return Err(close_error(&host, RhiStateHostErrorKind::InvalidEvidence).await);
    345         }
    346     };
    347     if require_migration_build(&metadata, build).is_err() {
    348         return Err(close_error(&host, RhiStateHostErrorKind::InvalidEvidence).await);
    349     }
    350     let state = RhiStateHost {
    351         host,
    352         mode: RhiStateHostMode::ReadWriteExisting,
    353         metadata,
    354     };
    355     if state_config::bind_or_verify(&state, state.metadata(), applied_at, build)
    356         .await
    357         .is_err()
    358     {
    359         return Err(close_error(&state.host, RhiStateHostErrorKind::InvalidEvidence).await);
    360     }
    361     Ok(state)
    362 }
    363 
    364 /// Applies one admitted RHI configuration while the service is offline.
    365 ///
    366 /// The function obtains exclusive writer authority, verifies the current
    367 /// durable binding, appends only bounded digest/public-identity/build evidence,
    368 /// and explicitly closes state before returning. It never stores raw TOML,
    369 /// paths, URLs, credential references, or protected identity material.
    370 pub async fn apply_rhi_configuration(
    371     runtime: &RhiRuntimeContext,
    372     current: &RhiConfigDocumentV1,
    373     candidate: &RhiConfigDocumentV1,
    374     applied_at: MigrationAppliedAtUnixSeconds,
    375     build: &MigrationBuildIdentity,
    376 ) -> Result<RhiConfigApplyOutcome, RhiConfigApplyError> {
    377     let state = open_rhi_state_read_write_from_config(runtime, current, applied_at, build)
    378         .await
    379         .map_err(|_| RhiConfigApplyError::new(RhiConfigApplyErrorKind::Binding))?;
    380     let candidate_metadata = match state_config::metadata_for_configuration(
    381         runtime,
    382         candidate,
    383         state.metadata().initial_database_metadata(),
    384     ) {
    385         Ok(metadata) => metadata,
    386         Err(error) => return Err(close_apply_error(&state, error.kind()).await),
    387     };
    388     if require_migration_build(&candidate_metadata, build).is_err() {
    389         return Err(close_apply_error(&state, RhiConfigApplyErrorKind::InvalidInput).await);
    390     }
    391     let outcome = state_config::append_configuration(
    392         &state,
    393         state.metadata(),
    394         &candidate_metadata,
    395         applied_at,
    396         build,
    397     )
    398     .await;
    399     let closed = state.close().await;
    400     if closed.is_err() {
    401         Err(RhiConfigApplyError::new(RhiConfigApplyErrorKind::Close))
    402     } else {
    403         outcome
    404     }
    405 }
    406 
    407 async fn close_apply_error(
    408     state: &RhiStateHost,
    409     fallback: RhiConfigApplyErrorKind,
    410 ) -> RhiConfigApplyError {
    411     if state.close().await.is_err() {
    412         RhiConfigApplyError::new(RhiConfigApplyErrorKind::Close)
    413     } else {
    414         RhiConfigApplyError::new(fallback)
    415     }
    416 }
    417 
    418 /// Opens an already initialized RHI catalog for immutable inspection.
    419 pub async fn open_rhi_state_inspection(
    420     runtime: &RhiRuntimeContext,
    421     metadata: &RhiStateMetadata,
    422 ) -> Result<RhiStateHost, RhiStateHostError> {
    423     let paths = state_paths(runtime)?;
    424     require_metadata(runtime, metadata)?;
    425     let identity = metadata.database_identity();
    426     let (migrations, schema) = catalogs()?;
    427     let host = ServiceSqliteHost::open_read_only_inspection(
    428         &paths,
    429         &identity,
    430         &migrations,
    431         &schema,
    432         ServiceSqliteConnectionOptions::reviewed(),
    433     )
    434     .await
    435     .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::InspectionOpen))?;
    436     let state = RhiStateHost {
    437         host,
    438         mode: RhiStateHostMode::ReadOnlyInspection,
    439         metadata: metadata.clone(),
    440     };
    441     if state_config::verify_binding(&state, metadata)
    442         .await
    443         .is_err()
    444     {
    445         return Err(close_error(&state.host, RhiStateHostErrorKind::InvalidEvidence).await);
    446     }
    447     Ok(state)
    448 }
    449 
    450 /// Opens existing inspection state from a sealed intent and actual metadata.
    451 pub async fn open_rhi_state_inspection_from_config(
    452     runtime: &RhiRuntimeContext,
    453     configuration: &RhiConfigDocumentV1,
    454 ) -> Result<RhiStateHost, RhiStateHostError> {
    455     let paths = state_paths(runtime)?;
    456     let (migrations, schema) = catalogs()?;
    457     let intent = existing_intent(&paths)?;
    458     let opened = ServiceSqliteHost::open_read_only_inspection_with_intent(
    459         &paths,
    460         &intent,
    461         &migrations,
    462         &schema,
    463         ServiceSqliteConnectionOptions::reviewed(),
    464     )
    465     .await
    466     .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::InspectionOpen))?;
    467     let (host, actual) = opened.into_parts();
    468     let metadata = match RhiStateMetadata::from_existing_database(runtime, configuration, &actual) {
    469         Ok(metadata) => metadata,
    470         Err(_) => {
    471             return Err(close_error(&host, RhiStateHostErrorKind::InvalidEvidence).await);
    472         }
    473     };
    474     let state = RhiStateHost {
    475         host,
    476         mode: RhiStateHostMode::ReadOnlyInspection,
    477         metadata,
    478     };
    479     if state_config::verify_binding(&state, state.metadata())
    480         .await
    481         .is_err()
    482     {
    483         return Err(close_error(&state.host, RhiStateHostErrorKind::InvalidEvidence).await);
    484     }
    485     Ok(state)
    486 }
    487 
    488 pub(crate) fn state_paths(
    489     runtime: &RhiRuntimeContext,
    490 ) -> Result<ServiceSqlitePaths, RhiStateHostError> {
    491     ServiceSqlitePaths::from_runtime_context(runtime.context())
    492         .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::InvalidPaths))
    493 }
    494 
    495 fn provision_state_directory(runtime: &RhiRuntimeContext) -> Result<(), RhiStateHostError> {
    496     runtime
    497         .context()
    498         .state_directory_plan()
    499         .and_then(|plan| plan.provision())
    500         .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Initialize))
    501 }
    502 
    503 pub(crate) fn require_metadata(
    504     runtime: &RhiRuntimeContext,
    505     metadata: &RhiStateMetadata,
    506 ) -> Result<(), RhiStateHostError> {
    507     let database = metadata.database();
    508     let matches = metadata.matches_runtime(runtime)
    509         && database.service() == runtime.context().service()
    510         && database.instance() == runtime.context().instance()
    511         && database.state_schema_version().get() == RHI_STATE_BASE_SCHEMA_VERSION
    512         && metadata
    513             .database_identity()
    514             .supported_state_schema_version()
    515             .get()
    516             == RHI_STATE_SCHEMA_VERSION;
    517     matches
    518         .then_some(())
    519         .ok_or_else(|| RhiStateHostError::new(RhiStateHostErrorKind::InvalidEvidence))
    520 }
    521 
    522 fn require_migration_build(
    523     metadata: &RhiStateMetadata,
    524     build: &MigrationBuildIdentity,
    525 ) -> Result<(), RhiStateHostError> {
    526     let versions = metadata.policy_versions();
    527     let matches = build.config_contract_version() == versions.configuration()
    528         && build.state_contract_version() == versions.state()
    529         && build.admin_contract_version() == versions.admin()
    530         && build.status_contract_version() == versions.status()
    531         && build.provider_contract_version() == versions.provider();
    532     matches
    533         .then_some(())
    534         .ok_or_else(|| RhiStateHostError::new(RhiStateHostErrorKind::InvalidEvidence))
    535 }
    536 
    537 fn exact_migration_outcome(outcome: radroots_service_sqlite::MigrationApplicationOutcome) -> bool {
    538     (RHI_STATE_BASE_SCHEMA_VERSION..=RHI_STATE_SCHEMA_VERSION).contains(&outcome.initial_version())
    539         && outcome.final_version() == RHI_STATE_SCHEMA_VERSION
    540         && outcome.applied_count() == RHI_STATE_SCHEMA_VERSION - outcome.initial_version()
    541 }
    542 
    543 fn existing_intent(
    544     paths: &ServiceSqlitePaths,
    545 ) -> Result<ExistingServiceDatabaseIntent, RhiStateHostError> {
    546     let version = core::num::NonZeroU32::new(RHI_STATE_SCHEMA_VERSION)
    547         .ok_or_else(|| RhiStateHostError::new(RhiStateHostErrorKind::Catalog))?;
    548     let application = ServiceSqliteApplicationId::new(RHI_STATE_APPLICATION_ID)
    549         .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Catalog))?;
    550     Ok(ExistingServiceDatabaseIntent::new(
    551         paths,
    552         version,
    553         application,
    554     ))
    555 }
    556 
    557 async fn close_error(
    558     host: &ServiceSqliteHost,
    559     fallback: RhiStateHostErrorKind,
    560 ) -> RhiStateHostError {
    561     if host.close().await.is_err() {
    562         RhiStateHostError::new(RhiStateHostErrorKind::Close)
    563     } else {
    564         RhiStateHostError::new(fallback)
    565     }
    566 }
    567 
    568 pub(crate) fn catalogs() -> Result<
    569     (
    570         radroots_service_sqlite::MigrationCatalog,
    571         radroots_service_sqlite::SchemaCatalog,
    572     ),
    573     RhiStateHostError,
    574 > {
    575     let migrations = rhi_migration_catalog()
    576         .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Catalog))?;
    577     let schema =
    578         rhi_schema_catalog().map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Catalog))?;
    579     validate_rhi_state_catalogs(&migrations, &schema)
    580         .map_err(|_| RhiStateHostError::new(RhiStateHostErrorKind::Catalog))?;
    581     Ok((migrations, schema))
    582 }
    583 
    584 fn initialize_empty_catalog<'a>(
    585     _initializer: &'a mut ServiceSqliteInitializer<'_>,
    586 ) -> ServiceSqliteInitializerFuture<'a, core::convert::Infallible> {
    587     Box::pin(async { Ok(()) })
    588 }