Skip to content

[CE-045] AppContext struct has no documentation comment explaining its lifecycle #85

Description

@Jaydbrown

Problem

AppContext (or the equivalent top-level application context struct) in the Core Engine has no documentation. Based on src/engine/mod.rs, the Engine struct is the central piece of the engine:

// src/engine/mod.rs
pub struct Engine {
    router: Router,
    store: PaymentStore,
    idempotency: IdempotencyStore,
    retry_config: RetryConfig,
}

None of these fields have doc comments. A developer or contributor reading the code cannot tell from the source alone:

  • What Router does (which adapter is selected for which urgency level?)
  • What PaymentStore is backed by (in-memory? Redis? SQLite?)
  • What IdempotencyStore prevents (duplicate payment submissions?)
  • Whether RetryConfig applies to the adapter submit call or to webhook delivery as well

Root Cause

Documentation was not written for the Engine struct or its fields during initial development.

Impact

  • New contributors must read through multiple files (src/router.rs, src/store.rs, src/idempotency.rs) to understand what Engine encapsulates
  • The Engine API surface (initiate, get, list, simulate, current_fees, health) is undocumented
  • Engine::new() takes adapters: Vec<Arc<dyn ChainAdapter>> and retry_config: RetryConfig — it's unclear if multiple adapters are used in parallel or as fallbacks

Fix

Add rustdoc comments to Engine and all its methods:

// src/engine/mod.rs

/// The core payment processing engine.
///
/// `Engine` manages the full lifecycle of a payment:
/// 1. **Validation** — Stellar address format, amount > 0, token allowlist
/// 2. **Routing** — selects the best `ChainAdapter` based on `Urgency` and current fee estimates
/// 3. **Submission** — calls `adapter.submit()` with exponential backoff retry
/// 4. **State tracking** — persists payment status in an in-memory `PaymentStore`
/// 5. **Idempotency** — prevents duplicate submissions via `IdempotencyStore`
///
/// # Example
///
/// ```rust
/// use std::sync::Arc;
/// use nodus_core_engine::engine::Engine;
/// use nodus_core_engine::retry::RetryConfig;
/// use nodus_core_engine::adapters::mock::MockAdapter;
///
/// let adapter = Arc::new(MockAdapter::success("tx_hash_123".into()));
/// let engine = Engine::new(vec![adapter], RetryConfig::default());
/// ```
pub struct Engine {
    /// Selects which `ChainAdapter` to use for a given payment urgency level.
    /// Falls back through adapters in priority order if the primary is unavailable.
    router: Router,
    /// In-memory store tracking payment state transitions:
    /// `Pending → Processing → Confirmed | Failed`.
    /// Note: this store is NOT persisted across restarts.
    store: PaymentStore,
    /// Prevents duplicate submissions for the same idempotency key.
    /// Keys expire after 24 hours.
    idempotency: IdempotencyStore,
    /// Configuration for exponential backoff retry on adapter submit failures.
    retry_config: RetryConfig,
}

impl Engine {
    /// Creates a new Engine with the given adapters and retry configuration.
    ///
    /// `adapters` must contain at least one adapter. The first adapter in the list
    /// is considered the "primary" for `Urgency::Standard`. Multiple adapters
    /// provide fallback routing when a primary adapter is unavailable.
    pub fn new(adapters: Vec<Arc<dyn ChainAdapter>>, retry_config: RetryConfig) -> Self { ... }

    /// Initiates a new payment and waits for confirmation or failure.
    ///
    /// This method blocks until the payment is confirmed on-chain or all retry
    /// attempts are exhausted. For fire-and-forget semantics, spawn this in a task.
    ///
    /// # Errors
    /// - `EngineError::InvalidRequest` — invalid address format, zero amount, or unknown token
    /// - `EngineError::NoAdapterAvailable` — all adapters report unavailable fees
    /// - `EngineError::NotFound` — internal error (should not occur)
    pub async fn initiate(
        &self,
        sender: String,
        recipient: String,
        amount: u64,
        token: String,
        urgency: Urgency,
    ) -> Result<Payment, EngineError> { ... }
}

Steps to Verify

  1. cargo doc --openEngine, Router, PaymentStore all have description text
  2. cargo doc 2>&1 | grep "missing documentation" — zero warnings
  3. A new contributor reading Engine::new() docs knows: "I need at least one adapter; first is primary"
  4. The initiate() error variants are all documented with conditions

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationpriority: lowCosmetic, docs, or minor improvements

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions