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.