Skip to content

hubuum-storage-core Rust API Policy

Status: experimental public API in the storage SDK 0.4 release train.

Purpose and Callers

hubuum-storage-core is the complete backend-neutral storage extension contract. It exposes capability traits, private-field DTOs, the bounded StorageError taxonomy, and the aggregate StorageBackend compile-time check. Backend crates may live outside this workspace and depend on the supported SDK graph without linking the server. Hubuum uses static Cargo composition; this is not a dynamic plugin ABI and has no runtime contract version handshake.

The normative semantics of that Rust surface are documented in the storage contract. The Rust declarations, semantic coverage inventory, and contract documentation must change together.

The crate also exposes the mandatory TransactionStorage unit of work. Applications compose safe lifecycle semantics through the crate-owned operation types returned by StorageTransaction; native connections and query interfaces remain private to each adapter.

Ordinary resource mutations require EventContext and return StorageMutationOutcome. A committed outcome includes a non-empty set of non-sensitive StorageAuditReceipt values for the durable events written atomically with the state change; a genuine no-op returns Unchanged. Imports and restores use explicit ImportStorage and RestoreStorage capabilities and do not weaken ordinary mutation signatures.

Backup snapshots validate revision and temporal-history consistency at their fallible constructor. Restore documents consume that validated source and prepare a complete replacement, including fresh current temporal snapshots for a history-free source. StorageRestoreDocument::new retains its existing signature; at_restore_boundary accepts an explicit boundary timestamp. Adapters must persist the prepared history even when source_includes_history is false.

Endpoint-set relation queries expose an optional max_results() bound. Adapters must apply that bound before materializing rows, after endpoint selection and visibility; zero requests no rows. new and into_parts retain their signatures, so read the bound before consuming the query. External adapters must implement the added bound before serving delegated traversal.

Task queries now optionally carry StorageTaskSearch through searching and search. The constructor and into_parts signatures remain compatible, but external adapters must read and apply the search before consuming the query. This is a behavioral contract change for adapters: ignoring the new predicates produces incorrect task rows and counts. TaskTimeRange validates half-open timestamp intervals; lifecycle sets and terminal restrictions are validated before storage access. No database migration is required for these lifecycle predicates.

Application composition supplies StorageObserver, keeping metrics exporters and global registries out of adapter-neutral contracts.

The root hubuum crate remains an internal application composition crate. HTTP clients should use Hubuum's versioned API instead of this storage API.

Compatibility

The crate follows the lockstep versioning, exact dependency, MSRV, deprecation, aggregate evolution, and adapter upgrade rules in the Storage Adapter SDK Compatibility policy. The release-train MSRV is Rust 1.88.

There are no feature flags. DTOs are in-memory Rust contracts, not durable or wire formats unless their documentation explicitly says otherwise. Backend implementations are expected to implement every supertrait of StorageBackend; focused test doubles may implement only the traits under test.

Lifecycle operations, record metadata, principal projections, and revision preconditions use hubuum-domain IDs and ResourceRevision. Revision targets are a closed semantic enum rather than adapter-formatted owner keys. Query methods accept validated hubuum-query values, and errors use storage-domain classifications rather than HTTP status or database-driver names. Native table, row, connection, query, and ETag representations are adapter or application concerns.

Computed-field create and import operations accept validated hubuum-computed-fields::Definition values. Adapters flatten a definition only at their persistence boundary and reconstruct it fallibly when reading stored rows; they must not expose an unvalidated parallel definition representation.

Task execution uses distinct active and terminal update types. Claims validate active status, lease presence, and task identity; completion construction validates the documented task-kind/artifact matrix before an adapter receives the request. Adapters must still compare the declared completion kind with the claimed persisted task.

Errors, Runtime, and Cancellation

Backend-specific errors must be classified into StorageError before returning through a storage trait. Applications translate StorageError into their own transport errors. Caller input must return an error rather than panic.

Async methods require a Send-capable executor but do not prescribe Tokio or an I/O driver. Dropping a returned future requests cancellation; a backend must document and test any operation that can continue or commit after cancellation. Multi-step writes that promise atomicity must use the backend's transaction mechanism. A TransactionStorage implementation commits when its callback returns Ok and rolls back when it returns Err. Transaction-scoped mutations inherit one required event context, and adapters must commit or roll back state and audit side effects together.

Security and Observability

Private fields and validating constructors preserve boundary invariants. Implementations must enforce visibility and permission inputs rather than treat them as hints. Debug implementations must remain bounded and redact identifiers, credentials, payloads, filters, and tokens where documented. Application composition wraps logical entrypoints with StorageObserver. Adapters may accept separate application-supplied native observers for implementation-level telemetry; both observer layers must use bounded capability and operation labels.

Ownership and Verification

Hubuum maintainers own the crate. The PostgreSQL adapter is the reference implementation, and shared compatibility tests exercise every statically registered backend. The experimental public hubuum-storage-conformance harness certifies durable receipts, no-op behavior, rollback, outbox-to-sink delivery, telemetry, exact revision conflicts, retention retry identity, delivery recovery, restore coordination rollback, and lease-loss finalization, while each backend owns native query, transaction, migration, connection-loss, and failure tests. External-crate integration tests implement all 44 complete-backend traits, compile every one of their 250 methods, exercise every transaction port, and name public construction paths for all current adapter-returned values. CI also packages the crate, builds rustdoc with warnings denied, and compares it with the latest crates.io release when a baseline exists.

Task discovery adds a storage SDK obligation: preserve the private-fielded, versioned StorageTaskMetadata on creation, completion, redaction and backup round trips. Validate persisted JSON once with from_persisted. Preserve unknown historical facts and update output summaries in the fenced finalization transaction. Artifact purge must not erase them.

Apply TaskDiscoverySearch predicates before counting and pagination, using its single captured evaluation timestamp. Project StorageTaskDiscoveryState from retained schema-work kind/status and artifact existence in bounded queries; never assemble schema reports during task polling. The PostgreSQL adapter requires migration 2026-09-18-000001_task_discovery.

Task authorization enrichment uses AuthorizationDataStorage::load_authorization_resources with a deduplicated StorageAuthorizationResourcesQuery. Adapters return lightweight StorageAuthorizationResource facts for all seven reference kinds, omit missing resources and relation endpoints, and bound queries by resource kind rather than page size. Preserve names and both relation endpoints for delegated policy checks; do not load template contents or remote transport/credential settings. Permission decisions remain with the configured authorization backend.

authorize_local_collection_batch returns one decision per input, in input order, using only the requested principals and collections. Preserve the single-check semantics: all requested permissions must occur in one group grant for that collection. Do not combine partial grants from different groups. Local permission batches use this operation for both endpoints of relations, including non-admin callers, without per-resource database calls.