Forráskód Böngészése

Import items rather than spell out fully-qualified paths inline

Writing a module-qualified path at the call site (kuatia_core::Account,
std::collections::hash_map::Entry::Vacant, impl std::fmt::Display) hides
which items a module actually depends on and adds a second, longer name
for something the reader must confirm resolves where they expect. It is
noisiest where a sibling from the same module is already imported and the
inline path is the odd one out.

Import the items and refer to them by their short names across the
workspace: pull Account/Plan/ReservationId/Entry into their use blocks in
the commit engine, event_dedup_key/AnyRow/AutoId in the storage backends,
and adopt the conventional `use std::fmt;` / `use std::error::Error;`
form for the Display and Error trait impls. Genuine one-off references
that would need a fresh import for a single use are left as they are.

No behavior change; this is import hygiene only.
Cesar Rodas 2 hete
szülő
commit
90f7bea3b4

+ 9 - 7
crates/kuatia-core/src/posting_resolution.rs

@@ -16,6 +16,8 @@
 //! they are reachable without standing up a store.
 
 use std::collections::HashMap;
+use std::error::Error;
+use std::fmt;
 
 use kuatia_types::{
     Account, AccountId, AssetId, Cent, Envelope, EnvelopeBuilder, NewPosting, OverflowError,
@@ -41,8 +43,8 @@ pub struct InsufficientFunds {
     pub requested: Cent,
 }
 
-impl std::fmt::Display for InsufficientFunds {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Display for InsufficientFunds {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
             "insufficient funds: available {}, requested {}",
@@ -51,7 +53,7 @@ impl std::fmt::Display for InsufficientFunds {
     }
 }
 
-impl std::error::Error for InsufficientFunds {}
+impl Error for InsufficientFunds {}
 
 /// Failure from resolution pass 2 ([`resolve_envelope`]).
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -62,8 +64,8 @@ pub enum ResolveError {
     Overflow,
 }
 
-impl std::fmt::Display for ResolveError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Display for ResolveError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::Selection(e) => write!(f, "selection: {e}"),
             Self::Overflow => write!(f, "monetary amount overflow"),
@@ -71,8 +73,8 @@ impl std::fmt::Display for ResolveError {
     }
 }
 
-impl std::error::Error for ResolveError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+impl Error for ResolveError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
         match self {
             Self::Selection(e) => Some(e),
             Self::Overflow => None,

+ 5 - 3
crates/kuatia-core/src/validate.rs

@@ -7,6 +7,8 @@
 //! [`PlanInput`]; this module never touches storage.
 
 use std::collections::{HashMap, HashSet};
+use std::error::Error;
+use std::fmt;
 
 use crate::hash::{account_hash, envelope_id};
 use kuatia_types::*;
@@ -129,8 +131,8 @@ pub enum ValidationError {
     Overflow,
 }
 
-impl std::fmt::Display for ValidationError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Display for ValidationError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::EmptyTransfer => write!(f, "transfer has no postings"),
             Self::DuplicateConsumedPosting(id) => write!(f, "duplicate consumed posting {id:?}"),
@@ -200,7 +202,7 @@ impl std::fmt::Display for ValidationError {
     }
 }
 
-impl std::error::Error for ValidationError {}
+impl Error for ValidationError {}
 
 impl From<OverflowError> for ValidationError {
     fn from(_: OverflowError) -> Self {

+ 11 - 12
crates/kuatia-dashboard/src/data.rs

@@ -3,6 +3,8 @@
 //! Everything here is read-only. Monetary values stay as raw [`Cent`] (minor
 //! units); presentation formats them.
 
+use std::cmp::Reverse;
+use std::fmt;
 use std::sync::Arc;
 
 use axum::{
@@ -10,6 +12,7 @@ use axum::{
     http::StatusCode,
     response::{IntoResponse, Response},
 };
+use kuatia::error::LedgerError;
 use kuatia::ledger::Ledger;
 use kuatia_core::{Account, AccountId, AssetId, Cent, PostingId, PostingState};
 use kuatia_storage::events::{LedgerEvent, LedgerEventKind};
@@ -18,7 +21,7 @@ use serde::Serialize;
 use tera::Tera;
 
 use crate::assets::AssetMeta;
-use crate::seed::account_label;
+use crate::seed::{EXTERNAL, account_label};
 
 /// Shared handler state.
 #[derive(Clone)]
@@ -219,10 +222,7 @@ pub async fn overview(state: &AppState) -> Result<OverviewDto, ApiError> {
     // mirrors everything in circulation.
     let mut issued = Vec::new();
     for asset in state.assets.iter() {
-        let external = state
-            .ledger
-            .balance(&crate::seed::EXTERNAL, &asset.id)
-            .await?;
+        let external = state.ledger.balance(&EXTERNAL, &asset.id).await?;
         let issued_value = external
             .checked_neg()
             .map_err(|_| ApiError::internal("overflow"))?;
@@ -281,7 +281,7 @@ pub async fn account_detail(state: &AppState, id: AccountId) -> Result<AccountDe
             status: posting_state_label(state).to_string(),
         })
         .collect();
-    postings.sort_by_key(|p| std::cmp::Reverse(p.value));
+    postings.sort_by_key(|p| Reverse(p.value));
 
     let transfers = state
         .ledger
@@ -315,7 +315,7 @@ pub async fn transfers(state: &AppState, limit: Option<u32>) -> Result<Vec<Trans
     };
     let page = state.ledger.query_transfers(&query).await?;
     let mut out: Vec<TransferDto> = page.items.iter().map(transfer_dto).collect();
-    out.sort_by_key(|t| std::cmp::Reverse(t.created_at));
+    out.sort_by_key(|t| Reverse(t.created_at));
     Ok(out)
 }
 
@@ -345,13 +345,13 @@ impl ApiError {
     }
 
     /// Build a 500 from any displayable error (used by the HTML render path).
-    pub fn from_display(err: impl std::fmt::Display) -> Self {
+    pub fn from_display(err: impl fmt::Display) -> Self {
         Self::internal(err.to_string())
     }
 
     /// Build a 400 from a displayable error (used for a malformed account id in
     /// the URL).
-    pub fn bad_request(err: impl std::fmt::Display) -> Self {
+    pub fn bad_request(err: impl fmt::Display) -> Self {
         Self {
             status: StatusCode::BAD_REQUEST,
             message: err.to_string(),
@@ -359,9 +359,8 @@ impl ApiError {
     }
 }
 
-impl From<kuatia::error::LedgerError> for ApiError {
-    fn from(err: kuatia::error::LedgerError) -> Self {
-        use kuatia::error::LedgerError;
+impl From<LedgerError> for ApiError {
+    fn from(err: LedgerError) -> Self {
         let status = match err {
             LedgerError::AccountNotFound(_) => StatusCode::NOT_FOUND,
             _ => StatusCode::INTERNAL_SERVER_ERROR,

+ 2 - 1
crates/kuatia-dashboard/src/main.rs

@@ -16,6 +16,7 @@ mod data;
 mod seed;
 mod ui;
 
+use std::error::Error;
 use std::sync::Arc;
 
 use axum::Router;
@@ -59,7 +60,7 @@ struct Cli {
 }
 
 #[tokio::main]
-async fn main() -> Result<(), Box<dyn std::error::Error>> {
+async fn main() -> Result<(), Box<dyn Error>> {
     tracing_subscriber::fmt()
         .with_env_filter(
             tracing_subscriber::EnvFilter::try_from_default_env()

+ 7 - 6
crates/kuatia-dashboard/src/seed.rs

@@ -2,6 +2,7 @@
 //! them from an external boundary account, then runs payments and a
 //! multi-asset trade so the dashboard has something to visualize.
 
+use std::error::Error;
 use std::sync::Arc;
 
 use kuatia::ledger::Ledger;
@@ -45,7 +46,7 @@ pub fn account_label(id: AccountId) -> Option<&'static str> {
 /// connection its own separate database, so more than one would split the
 /// ledger; one connection is also fine for a low-traffic dashboard on a file or
 /// Postgres backend.
-pub async fn connect(db_url: &str) -> Result<Arc<Ledger>, Box<dyn std::error::Error>> {
+pub async fn connect(db_url: &str) -> Result<Arc<Ledger>, Box<dyn Error>> {
     sqlx::any::install_default_drivers();
     let pool = sqlx::any::AnyPoolOptions::new()
         .max_connections(1)
@@ -73,7 +74,7 @@ fn sqlite_creatable(db_url: &str) -> String {
 /// it seeded, `false` if the ledger was already populated (so re-running with
 /// `--seed` against a persistent database is a safe no-op rather than a
 /// duplicate-id error).
-pub async fn seed_if_empty(ledger: &Arc<Ledger>) -> Result<bool, Box<dyn std::error::Error>> {
+pub async fn seed_if_empty(ledger: &Arc<Ledger>) -> Result<bool, Box<dyn Error>> {
     if !ledger.list_accounts().await?.is_empty() {
         return Ok(false);
     }
@@ -82,7 +83,7 @@ pub async fn seed_if_empty(ledger: &Arc<Ledger>) -> Result<bool, Box<dyn std::er
 }
 
 /// Populate the ledger with demo accounts and a spread of transfers.
-pub async fn populate(ledger: &Arc<Ledger>) -> Result<(), Box<dyn std::error::Error>> {
+pub async fn populate(ledger: &Arc<Ledger>) -> Result<(), Box<dyn Error>> {
     // Two-decimal assets (USD, EUR) and an 8-decimal asset (BTC).
     let fiat = Amount::new(2);
     let btc = Amount::new(8);
@@ -130,7 +131,7 @@ async fn create(
     ledger: &Arc<Ledger>,
     id: AccountId,
     debit_must_not_exceed_credit: bool,
-) -> Result<(), Box<dyn std::error::Error>> {
+) -> Result<(), Box<dyn Error>> {
     let account = if debit_must_not_exceed_credit {
         Account::debit_must_not_exceed_credit(id)
     } else {
@@ -145,7 +146,7 @@ async fn deposit(
     to: AccountId,
     asset: AssetId,
     amount: Cent,
-) -> Result<(), Box<dyn std::error::Error>> {
+) -> Result<(), Box<dyn Error>> {
     let transfer = TransferBuilder::new()
         .deposit(to, asset, amount, EXTERNAL)?
         .build();
@@ -159,7 +160,7 @@ async fn pay(
     to: AccountId,
     asset: AssetId,
     amount: Cent,
-) -> Result<(), Box<dyn std::error::Error>> {
+) -> Result<(), Box<dyn Error>> {
     let transfer = TransferBuilder::new().pay(from, to, asset, amount).build();
     ledger.commit(transfer).await?;
     Ok(())

+ 4 - 4
crates/kuatia-dashboard/src/ui.rs

@@ -13,7 +13,7 @@ use axum::{
     response::{Html, IntoResponse, Response},
     routing::get,
 };
-use kuatia_core::{Amount, AssetId, Cent};
+use kuatia_core::{AccountId, Amount, AssetId, Cent};
 use serde::Serialize;
 use tera::{Context, Tera};
 
@@ -261,13 +261,13 @@ fn civil_from_days(z: i64) -> (i64, u32, u32) {
 // ---------------------------------------------------------------------------
 
 /// Display an account id as its IBAN-style code in grouped (spaced) format.
-fn acct_display(id: kuatia_core::AccountId) -> String {
+fn acct_display(id: AccountId) -> String {
     id.to_grouped()
 }
 
 /// The detail route path for an account, keyed by the machine-format code:
 /// `/accounts/<code>`.
-fn acct_link(id: kuatia_core::AccountId) -> String {
+fn acct_link(id: AccountId) -> String {
     format!("/accounts/{id}")
 }
 
@@ -388,7 +388,7 @@ async fn accounts_ctx(state: &AppState) -> Result<Context, ApiError> {
     Ok(ctx)
 }
 
-async fn account_ctx(state: &AppState, id: kuatia_core::AccountId) -> Result<Context, ApiError> {
+async fn account_ctx(state: &AppState, id: AccountId) -> Result<Context, ApiError> {
     let dto = data::account_detail(state, id).await?;
     let mut ctx = Context::new();
     ctx.insert("nav", "accounts");

+ 4 - 3
crates/kuatia-money/src/lib.rs

@@ -13,6 +13,7 @@
 //! never silently round or overflow.
 
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::error::Error;
 use std::fmt;
 use std::str::FromStr;
 
@@ -148,7 +149,7 @@ impl fmt::Display for OverflowError {
     }
 }
 
-impl std::error::Error for OverflowError {}
+impl Error for OverflowError {}
 
 /// Returned when a string cannot be parsed into a [`Cent`].
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -160,7 +161,7 @@ impl fmt::Display for ParseCentError {
     }
 }
 
-impl std::error::Error for ParseCentError {}
+impl Error for ParseCentError {}
 
 impl Cent {
     /// The zero amount.
@@ -326,7 +327,7 @@ impl fmt::Display for ParseAmountError {
     }
 }
 
-impl std::error::Error for ParseAmountError {}
+impl Error for ParseAmountError {}
 
 impl Amount {
     /// Create an `Amount` formatter with the given number of decimal places.

+ 9 - 7
crates/kuatia-storage-sql/src/lib.rs

@@ -15,12 +15,14 @@ use std::str::FromStr;
 use std::sync::atomic::{AtomicU8, Ordering};
 
 use async_trait::async_trait;
+use sqlx::any::AnyRow;
 use sqlx::{Any, Pool, Row};
 
 use kuatia_storage::error::StoreError;
-use kuatia_storage::events::{EventStore, LedgerEvent};
+use kuatia_storage::events::{EventStore, LedgerEvent, event_dedup_key};
 use kuatia_storage::query::{filter_transfers, paginate};
 use kuatia_storage::store::*;
+use kuatia_types::autoid::AutoId;
 use kuatia_types::*;
 
 // Cached backend kind for `SqlStore::backend`.
@@ -36,7 +38,7 @@ const FOR_UPDATE: &str = " FOR UPDATE";
 /// SQL-backed [`Store`] implementation.
 pub struct SqlStore {
     pool: Pool<Any>,
-    autoid: kuatia_types::autoid::AutoId,
+    autoid: AutoId,
     /// Detected backend kind (lazily probed): one of `BACKEND_*`.
     backend: AtomicU8,
 }
@@ -46,7 +48,7 @@ impl SqlStore {
     pub fn new(pool: Pool<Any>) -> Self {
         Self {
             pool,
-            autoid: kuatia_types::autoid::AutoId::new(),
+            autoid: AutoId::new(),
             backend: AtomicU8::new(BACKEND_UNKNOWN),
         }
     }
@@ -223,7 +225,7 @@ fn envelope_id_from_hex(s: &str) -> Result<EnvelopeId, StoreError> {
     Ok(EnvelopeId(arr))
 }
 
-fn row_to_account(row: &sqlx::any::AnyRow) -> Result<Account, StoreError> {
+fn row_to_account(row: &AnyRow) -> Result<Account, StoreError> {
     let id: i64 = row
         .try_get("id")
         .map_err(|e| StoreError::Internal(e.to_string()))?;
@@ -252,7 +254,7 @@ fn row_to_account(row: &sqlx::any::AnyRow) -> Result<Account, StoreError> {
     })
 }
 
-fn row_to_posting(row: &sqlx::any::AnyRow) -> Result<Posting, StoreError> {
+fn row_to_posting(row: &AnyRow) -> Result<Posting, StoreError> {
     let transfer_id: String = row
         .try_get("transfer_id")
         .map_err(|e| StoreError::Internal(e.to_string()))?;
@@ -637,7 +639,7 @@ impl PostingStore for SqlStore {
 
         // Key membership by the same `(hex, idx)` values that were bound, so the
         // per-id lookup below matches without decoding transfer ids back.
-        let row_key = |row: &sqlx::any::AnyRow| -> Result<(String, i16), StoreError> {
+        let row_key = |row: &AnyRow| -> Result<(String, i16), StoreError> {
             let transfer_id: String = row
                 .try_get("transfer_id")
                 .map_err(|e| StoreError::Internal(e.to_string()))?;
@@ -1253,7 +1255,7 @@ impl EventStore for SqlStore {
         // Idempotent on the dedup key: a replayed transfer or lifecycle-transition
         // event conflicts on `dedup_key` and returns the existing seq instead of a
         // duplicate row.
-        match kuatia_storage::events::event_dedup_key(&event.kind) {
+        match event_dedup_key(&event.kind) {
             Some(dedup_key) => {
                 let res = sqlx::query("INSERT INTO events (seq, timestamp, kind, data, dedup_key) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (dedup_key) DO NOTHING")
                     .bind(seq as i64)

+ 6 - 3
crates/kuatia-storage/src/error.rs

@@ -1,5 +1,8 @@
 //! Error types for storage implementations.
 
+use std::error::Error;
+use std::fmt;
+
 /// Errors produced by [`Store`](crate::store::Store) implementations.
 ///
 /// The store is a dumb instruction follower: writes report affected-row counts,
@@ -15,8 +18,8 @@ pub enum StoreError {
     Internal(String),
 }
 
-impl std::fmt::Display for StoreError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Display for StoreError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::NotFound(msg) => write!(f, "not found: {msg}"),
             Self::Internal(msg) => write!(f, "internal error: {msg}"),
@@ -24,4 +27,4 @@ impl std::fmt::Display for StoreError {
     }
 }
 
-impl std::error::Error for StoreError {}
+impl Error for StoreError {}

+ 5 - 5
crates/kuatia-storage/src/mem_store.rs

@@ -4,6 +4,7 @@
 
 use async_trait::async_trait;
 use std::collections::HashMap;
+use std::collections::hash_map::Entry;
 use tokio::sync::RwLock;
 
 use kuatia_types::autoid::AutoId;
@@ -13,7 +14,7 @@ use kuatia_types::{
 };
 
 use crate::error::StoreError;
-use crate::events::{EventStore, LedgerEvent};
+use crate::events::{EventStore, LedgerEvent, event_dedup_key};
 use crate::query::{filter_transfers, paginate};
 use crate::store::{
     AccountStore, BalanceProjection, BalanceProjectionStore, BookStore, EnvelopeRecord, Page,
@@ -339,8 +340,7 @@ impl PostingStore for InMemoryStore {
         let mut store = self.postings.write().await;
         let mut inserted: u64 = 0;
         for posting in postings {
-            if let std::collections::hash_map::Entry::Vacant(e) = store.immutable.entry(posting.id)
-            {
+            if let Entry::Vacant(e) = store.immutable.entry(posting.id) {
                 e.insert(posting.clone());
                 // Only newly-inserted postings are activated; a since-spent
                 // posting is not re-activated on a replayed insert. The active
@@ -465,10 +465,10 @@ impl EventStore for InMemoryStore {
         let mut events = self.events.write().await;
         // Idempotent on the dedup key: a replayed transfer or lifecycle-transition
         // event returns the existing seq instead of inserting a duplicate.
-        if let Some(key) = crate::events::event_dedup_key(&event.kind)
+        if let Some(key) = event_dedup_key(&event.kind)
             && let Some(existing) = events
                 .iter()
-                .find(|e| crate::events::event_dedup_key(&e.kind).as_deref() == Some(key.as_str()))
+                .find(|e| event_dedup_key(&e.kind).as_deref() == Some(key.as_str()))
         {
             return Ok(existing.seq);
         }

+ 6 - 4
crates/kuatia-types/src/account_code.rs

@@ -4,7 +4,7 @@
 //! 18-character base-36 body followed by two ISO 7064 mod-97 check digits, with
 //! no country code. It is produced and consumed through a narrow interface of
 //! three methods on [`AccountId`]: [`Display`](fmt::Display) (machine form),
-//! [`FromStr`](std::str::FromStr) (validating parse), and
+//! [`FromStr`] (validating parse), and
 //! [`to_grouped`](AccountId::to_grouped) (presentation spacing).
 //!
 //! Everything behind that interface is private: bit-packing the `(id, sub)`
@@ -16,7 +16,9 @@
 //! encodable range and to key the deployment's codes.
 
 use crate::AccountId;
+use std::error::Error;
 use std::fmt;
+use std::str::FromStr;
 use std::sync::atomic::{AtomicU64, Ordering};
 
 // ---------------------------------------------------------------------------
@@ -225,7 +227,7 @@ impl fmt::Display for AccountId {
     /// country code. The `(id, sub)` pair is packed into a 93-bit value and run
     /// through a keyed format-preserving permutation (see [`set_id_seed`]) before
     /// encoding, so the body does not reveal the raw ids. Round-trips via
-    /// [`FromStr`](std::str::FromStr); [`to_grouped`](AccountId::to_grouped) adds
+    /// [`FromStr`]; [`to_grouped`](AccountId::to_grouped) adds
     /// the presentation spacing (five groups of four).
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let body = base36_body(obfuscate(pack(self.id, self.sub), id_seed()));
@@ -262,9 +264,9 @@ impl fmt::Display for ParseAccountIdError {
     }
 }
 
-impl std::error::Error for ParseAccountIdError {}
+impl Error for ParseAccountIdError {}
 
-impl std::str::FromStr for AccountId {
+impl FromStr for AccountId {
     type Err = ParseAccountIdError;
 
     /// Parse an IBAN-style account code back into the two legs. Any spaces

+ 4 - 3
crates/kuatia-types/src/lib.rs

@@ -13,6 +13,7 @@ pub use account_code::{
     DEFAULT_ID_SEED, ID_BITS, ParseAccountIdError, SUB_BITS, id_seed, set_id_seed,
 };
 
+use crate::autoid::AutoId;
 use serde::{Deserialize, Serialize};
 use std::collections::BTreeMap;
 use std::fmt;
@@ -139,7 +140,7 @@ impl Default for AccountId {
     fn default() -> Self {
         // Process-global generator: a per-thread one could mint the same id on
         // two threads within a millisecond, yielding duplicate account ids.
-        static GEN: crate::autoid::AutoId = crate::autoid::AutoId::new();
+        static GEN: AutoId = AutoId::new();
         Self {
             id: GEN.next(),
             sub: 0,
@@ -220,7 +221,7 @@ impl BookId {
     pub fn generate() -> Self {
         // Process-global so the "process-unique" contract holds across threads;
         // a per-thread generator can repeat an id on another thread.
-        static GEN: crate::autoid::AutoId = crate::autoid::AutoId::new();
+        static GEN: AutoId = AutoId::new();
         Self(GEN.next())
     }
 }
@@ -251,7 +252,7 @@ impl Default for ReservationId {
         // generator lets two sagas on different threads mint the same id within
         // a millisecond, which collapses the reservation-ownership check and
         // allows a double-spend under concurrency.
-        static GEN: crate::autoid::AutoId = crate::autoid::AutoId::new();
+        static GEN: AutoId = AutoId::new();
         Self(GEN.next())
     }
 }

+ 7 - 4
crates/kuatia/src/error.rs

@@ -3,6 +3,9 @@
 //! [`LedgerError`] unifies errors from the pure core (validation, selection)
 //! and from storage, so callers get a single error type from every API.
 
+use std::error::Error;
+use std::fmt;
+
 use kuatia_core::{
     AccountId, AssetId, BookId, EnvelopeId, InsufficientFunds, OverflowError, PostingId,
     ResolveError, ValidationError,
@@ -78,8 +81,8 @@ pub enum LedgerError {
     },
 }
 
-impl std::fmt::Display for LedgerError {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Display for LedgerError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::Validation(e) => write!(f, "validation: {e}"),
             Self::Store(e) => write!(f, "store: {e}"),
@@ -122,8 +125,8 @@ impl std::fmt::Display for LedgerError {
     }
 }
 
-impl std::error::Error for LedgerError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+impl Error for LedgerError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
         match self {
             Self::Validation(e) => Some(e),
             Self::Store(e) => Some(e),

+ 2 - 2
crates/kuatia/src/inflight.rs

@@ -17,7 +17,7 @@ use std::sync::Arc;
 
 use kuatia_core::{
     Account, AccountFlags, AccountId, AssetId, BookId, Cent, EnvelopeId, InsufficientFunds,
-    Metadata, Receipt, Transfer, TransferBuilder, hash::double_sha256,
+    Metadata, Receipt, SUB_BITS, Transfer, TransferBuilder, hash::double_sha256,
 };
 use kuatia_storage::error::StoreError;
 use kuatia_storage::store::EnvelopeRecord;
@@ -565,7 +565,7 @@ fn inflight_subaccount(transfer: &Transfer) -> i64 {
     first.copy_from_slice(&hash[..8]);
     // Keep only the low SUB_BITS so the hold's subaccount id fits the account
     // code's encodable range (ADR-0015). The result is always positive.
-    let mask = (1u64 << kuatia_types::SUB_BITS) - 1;
+    let mask = (1u64 << SUB_BITS) - 1;
     (u64::from_be_bytes(first) & mask) as i64
 }
 

+ 17 - 20
crates/kuatia/src/ledger/commit.rs

@@ -7,16 +7,17 @@
 //! crash.
 
 use std::collections::HashMap;
+use std::collections::hash_map::Entry;
 use std::sync::Arc;
 
 use legend::ExecutionResult;
 use tracing::instrument;
 
 use kuatia_core::{
-    AccountId, AccountSnapshotId, AssetId, Book, Cent, DEFAULT_BOOK, Envelope, EnvelopeBuilder,
-    EnvelopeId, NewPosting, PlanInput, Posting, PostingFilter, PostingId, PostingState, Receipt,
-    ResolveInput, Transfer, account_snapshot_id, draft_movements, envelope_id, resolve_envelope,
-    validate_and_plan,
+    Account, AccountId, AccountSnapshotId, AssetId, Book, Cent, DEFAULT_BOOK, Envelope,
+    EnvelopeBuilder, EnvelopeId, NewPosting, Plan, PlanInput, Posting, PostingFilter, PostingId,
+    PostingState, Receipt, ReservationId, ResolveInput, Transfer, account_snapshot_id,
+    draft_movements, envelope_id, resolve_envelope, validate_and_plan,
 };
 
 use kuatia_storage::error::StoreError;
@@ -47,7 +48,7 @@ enum SagaPhase {
 #[derive(serde::Serialize, serde::Deserialize)]
 struct PendingSaga {
     envelope: Envelope,
-    reservation: kuatia_core::ReservationId,
+    reservation: ReservationId,
     phase: SagaPhase,
 }
 
@@ -59,7 +60,7 @@ struct PendingSaga {
 #[derive(serde::Serialize, serde::Deserialize)]
 pub(super) struct PendingTransition {
     /// The next account version to append: version already bumped, flag flipped.
-    pub next: kuatia_core::Account,
+    pub next: Account,
     /// The lifecycle event paired with this version bump. It carries the target
     /// version, so re-appending it on recovery dedups to the original.
     pub event: LedgerEventKind,
@@ -81,7 +82,7 @@ struct LoadedState {
     /// Postings being consumed by the envelope.
     consumed_postings: Vec<Posting>,
     /// Accounts referenced by the envelope.
-    accounts: HashMap<AccountId, kuatia_core::Account>,
+    accounts: HashMap<AccountId, Account>,
     /// Current balances for all referenced (account, asset) pairs.
     balances: HashMap<(AccountId, AssetId), Cent>,
     /// The book gating this transfer, if one is loaded (`None` = unrestricted default).
@@ -147,11 +148,7 @@ impl Ledger {
     }
 
     /// Run pure validation over the loaded state and produce a plan.
-    fn plan(
-        &self,
-        envelope: &Envelope,
-        loaded: &LoadedState,
-    ) -> Result<kuatia_core::Plan, LedgerError> {
+    fn plan(&self, envelope: &Envelope, loaded: &LoadedState) -> Result<Plan, LedgerError> {
         let input = PlanInput {
             envelope,
             consumed_postings: &loaded.consumed_postings,
@@ -185,7 +182,7 @@ impl Ledger {
         // to zero on the system account, so it produces no debit and loads nothing
         // here.
         let mut available: HashMap<(AccountId, AssetId), Vec<Posting>> = HashMap::new();
-        let mut accounts: HashMap<AccountId, kuatia_core::Account> = HashMap::new();
+        let mut accounts: HashMap<AccountId, Account> = HashMap::new();
         for debit in &draft.debits {
             let postings = self
                 .store
@@ -197,7 +194,7 @@ impl Ledger {
                 )
                 .await?;
             available.insert((debit.account, debit.asset), postings);
-            if let std::collections::hash_map::Entry::Vacant(e) = accounts.entry(debit.account) {
+            if let Entry::Vacant(e) = accounts.entry(debit.account) {
                 e.insert(self.store.get_account(&debit.account).await?);
             }
         }
@@ -257,7 +254,7 @@ impl Ledger {
 
         // Write-ahead: persist {envelope, reservation, phase=Reserving} before any
         // mutation. The finalize step bumps the phase to Finalizing.
-        let reservation = kuatia_core::ReservationId::default();
+        let reservation = ReservationId::default();
         let saga_id = reservation.0;
         self.save_pending(&envelope, reservation, SagaPhase::Reserving)
             .await?;
@@ -286,7 +283,7 @@ impl Ledger {
     async fn drive_envelope_saga(
         self: &Arc<Self>,
         envelope: Envelope,
-        reservation: kuatia_core::ReservationId,
+        reservation: ReservationId,
     ) -> Result<Receipt, LedgerError> {
         let saga = EnvelopeSaga::new(EnvelopeSagaInputs {
             reserve: ReserveInput,
@@ -404,7 +401,7 @@ impl Ledger {
     pub(crate) async fn finalize_envelope(
         &self,
         envelope: &Envelope,
-        reservation: kuatia_core::ReservationId,
+        reservation: ReservationId,
     ) -> Result<Receipt, LedgerError> {
         let tid = envelope_id(envelope);
         if let Some(record) = self.store.get_transfer(&tid).await? {
@@ -538,7 +535,7 @@ impl Ledger {
     async fn save_pending(
         &self,
         envelope: &Envelope,
-        reservation: kuatia_core::ReservationId,
+        reservation: ReservationId,
         phase: SagaPhase,
     ) -> Result<(), LedgerError> {
         let blob = serde_json::to_vec(&PendingRecord::Envelope(PendingSaga {
@@ -557,10 +554,10 @@ impl Ledger {
     /// key never collides with an in-flight commit saga's key.
     pub(super) async fn save_transition(
         &self,
-        next: &kuatia_core::Account,
+        next: &Account,
         event: &LedgerEventKind,
     ) -> Result<i64, LedgerError> {
-        let saga_id = kuatia_core::ReservationId::default().0;
+        let saga_id = ReservationId::default().0;
         let blob = serde_json::to_vec(&PendingRecord::Transition(PendingTransition {
             next: next.clone(),
             event: event.clone(),

+ 2 - 2
crates/kuatia/src/ledger/lifecycle.rs

@@ -11,7 +11,7 @@
 
 use tracing::instrument;
 
-use kuatia_core::{AccountFlags, AccountId, PostingFilter};
+use kuatia_core::{Account, AccountFlags, AccountId, PostingFilter};
 use kuatia_storage::events::{LedgerEvent, LedgerEventKind};
 
 use super::{Ledger, now_millis};
@@ -19,7 +19,7 @@ use crate::error::LedgerError;
 
 impl Ledger {
     /// Create a new account and emit an AccountCreated event.
-    pub async fn create_account(&self, account: kuatia_core::Account) -> Result<(), LedgerError> {
+    pub async fn create_account(&self, account: Account) -> Result<(), LedgerError> {
         let id = account.id;
         if self.store.create_account(account).await? == 0 {
             return Err(LedgerError::AccountAlreadyExists(id));

+ 2 - 2
crates/kuatia/src/ledger/projection.rs

@@ -15,7 +15,7 @@ use std::sync::Arc;
 use tracing::instrument;
 
 use kuatia_core::{AccountId, AssetId, Cent, PostingId};
-use kuatia_storage::store::{Store, TransferQuery};
+use kuatia_storage::store::{EnvelopeRecord, Store, TransferQuery};
 
 use super::{Ledger, now_millis};
 use crate::error::LedgerError;
@@ -29,7 +29,7 @@ async fn fold_account_delta(
     store: &dyn Store,
     account: &AccountId,
     asset: &AssetId,
-    records: &[kuatia_storage::store::EnvelopeRecord],
+    records: &[EnvelopeRecord],
 ) -> Result<(Cent, u64), LedgerError> {
     let mut delta = Cent::ZERO;
     let mut count: u64 = 0;

+ 16 - 28
crates/kuatia/src/ledger/query.rs

@@ -5,20 +5,23 @@
 //! underlying store is reachable via [`Ledger::store`] for callers that want the
 //! raw storage error instead.
 
-use kuatia_core::{AccountId, PostingFilter, PostingId, PostingState};
+use kuatia_core::{
+    Account, AccountId, Book, BookId, Posting, PostingFilter, PostingId, PostingState,
+};
 use kuatia_storage::events::LedgerEvent;
 
 use super::Ledger;
 use crate::error::LedgerError;
+use crate::store::{EnvelopeRecord, Page, PostingQuery, TransferQuery};
 
 impl Ledger {
     /// List all accounts (latest version of each).
-    pub async fn list_accounts(&self) -> Result<Vec<kuatia_core::Account>, LedgerError> {
+    pub async fn list_accounts(&self) -> Result<Vec<Account>, LedgerError> {
         Ok(self.store.list_accounts().await?)
     }
 
     /// Fetch a single account by id.
-    pub async fn get_account(&self, id: &AccountId) -> Result<kuatia_core::Account, LedgerError> {
+    pub async fn get_account(&self, id: &AccountId) -> Result<Account, LedgerError> {
         self.store
             .get_account(id)
             .await
@@ -26,10 +29,7 @@ impl Ledger {
     }
 
     /// Return all transfers involving the given account (exact subaccount).
-    pub async fn history(
-        &self,
-        account: &AccountId,
-    ) -> Result<Vec<crate::store::EnvelopeRecord>, LedgerError> {
+    pub async fn history(&self, account: &AccountId) -> Result<Vec<EnvelopeRecord>, LedgerError> {
         Ok(self
             .store
             .get_transfers_for_account(account.id, Some(account.sub))
@@ -39,16 +39,13 @@ impl Ledger {
     /// Query transfers with filtering and pagination.
     pub async fn query_transfers(
         &self,
-        query: &crate::store::TransferQuery,
-    ) -> Result<crate::store::Page<crate::store::EnvelopeRecord>, LedgerError> {
+        query: &TransferQuery,
+    ) -> Result<Page<EnvelopeRecord>, LedgerError> {
         Ok(self.store.query_transfers(query).await?)
     }
 
     /// Return all postings (any state) for the given account.
-    pub async fn postings(
-        &self,
-        account: &AccountId,
-    ) -> Result<Vec<kuatia_core::Posting>, LedgerError> {
+    pub async fn postings(&self, account: &AccountId) -> Result<Vec<Posting>, LedgerError> {
         Ok(self
             .store
             .get_postings_by_account(account.id, Some(account.sub), None, PostingFilter::All)
@@ -60,7 +57,7 @@ impl Ledger {
     pub async fn postings_with_state(
         &self,
         account: &AccountId,
-    ) -> Result<Vec<(kuatia_core::Posting, PostingState)>, LedgerError> {
+    ) -> Result<Vec<(Posting, PostingState)>, LedgerError> {
         let postings = self.postings(account).await?;
         let ids: Vec<PostingId> = postings.iter().map(|p| p.id).collect();
         let states = self.store.get_posting_states(&ids).await?;
@@ -68,23 +65,17 @@ impl Ledger {
     }
 
     /// Query postings with filtering and pagination.
-    pub async fn query_postings(
-        &self,
-        query: &crate::store::PostingQuery,
-    ) -> Result<crate::store::Page<kuatia_core::Posting>, LedgerError> {
+    pub async fn query_postings(&self, query: &PostingQuery) -> Result<Page<Posting>, LedgerError> {
         Ok(self.store.query_postings(query).await?)
     }
 
     /// Return the full version history for an account.
-    pub async fn account_history(
-        &self,
-        id: &AccountId,
-    ) -> Result<Vec<kuatia_core::Account>, LedgerError> {
+    pub async fn account_history(&self, id: &AccountId) -> Result<Vec<Account>, LedgerError> {
         Ok(self.store.get_account_history(id).await?)
     }
 
     /// Create a new book.
-    pub async fn create_book(&self, book: kuatia_core::Book) -> Result<(), LedgerError> {
+    pub async fn create_book(&self, book: Book) -> Result<(), LedgerError> {
         let id = book.id;
         if self.store.create_book(book).await? == 0 {
             return Err(LedgerError::BookAlreadyExists(id));
@@ -93,15 +84,12 @@ impl Ledger {
     }
 
     /// Fetch a book by id.
-    pub async fn get_book(
-        &self,
-        id: &kuatia_core::BookId,
-    ) -> Result<kuatia_core::Book, LedgerError> {
+    pub async fn get_book(&self, id: &BookId) -> Result<Book, LedgerError> {
         Ok(self.store.get_book(id).await?)
     }
 
     /// List all books.
-    pub async fn list_books(&self) -> Result<Vec<kuatia_core::Book>, LedgerError> {
+    pub async fn list_books(&self) -> Result<Vec<Book>, LedgerError> {
         Ok(self.store.list_books().await?)
     }
 

+ 5 - 3
crates/kuatia/src/saga.rs

@@ -23,6 +23,8 @@
 //! High-level steps (`PayMovementStep` and `DepositMovementStep`) compose over
 //! the intent-layer API and can be combined into multi-transfer sagas via `legend!`.
 
+use std::fmt;
+use std::future::Future;
 use std::sync::Arc;
 
 use async_trait::async_trait;
@@ -65,7 +67,7 @@ pub(crate) async fn apply_and_verify<F, Fut>(
 ) -> Result<(), LedgerError>
 where
     F: FnOnce() -> Fut,
-    Fut: std::future::Future<Output = Result<bool, LedgerError>>,
+    Fut: Future<Output = Result<bool, LedgerError>>,
 {
     if count == target as u64 {
         return Ok(());
@@ -121,8 +123,8 @@ pub struct LedgerCtx {
     ledger: Option<Arc<Ledger>>,
 }
 
-impl std::fmt::Debug for LedgerCtx {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Debug for LedgerCtx {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("LedgerCtx")
             .field("receipts", &self.receipts)
             .field("reserved_postings", &self.reserved_postings.len())