Storage Adapter SDK Compatibility¶
Status: accepted; current experimental release train is 0.4.
Supported Crate Graph¶
The statically linked storage adapter SDK consists of these crates:
| Crate | Supported purpose | Supported features |
|---|---|---|
hubuum-computed-fields |
Validated computed-field definitions and deterministic evaluation | Default only |
hubuum-schema-diagnostics |
Generic bounded diagnostics for jsonschema errors |
Default; openapi |
hubuum-domain |
Validated identifiers, revisions, JSON Patch, and domain values | Default; openapi |
hubuum-events-core |
Event catalog, envelopes, filters, and mutation provenance | Default; schema |
hubuum-query |
Bounded, backend-neutral query parsing and values | Default only |
hubuum-task-core |
Task identity, idempotency, validated execution limits and cooperative stop contexts | Default only |
hubuum-storage-core |
Complete capability traits, DTOs, errors, transactions, and aggregate | Default only |
hubuum-storage-conformance |
Reusable behavioral certification for complete adapters | Default only |
The diagnostic crate is independently usable and has no Hubuum dependencies. It is currently a publishable prerequisite in this train; actual standalone publication and a separate release cadence require a later review.
Their publication graph is closed:
hubuum-storage-conformance
| |
| +-- hubuum-domain
v
hubuum-storage-core
| | | | |
| | | | +-- hubuum-task-core
| | | +---------- hubuum-query
| | +------------------ hubuum-events-core
| +-------------------------- hubuum-domain
+---------------------------------- hubuum-computed-fields
hubuum-domain --> hubuum-schema-diagnostics
Every in-graph dependency uses an exact version requirement. The eight packages
share one version and are released together. The root application and
hubuum-storage-postgres are not part of the supported SDK. PostgreSQL remains
the in-repository reference implementation, while an external adapter depends
only on the graph above.
The SDK is a Rust source compatibility contract for static Cargo composition. It is not a dynamic plugin ABI, wire protocol, runtime capability handshake, or server embedding API.
Versioning and Aggregate Evolution¶
The SDK remains experimental-public during the 0.x series:
- a patch release is source compatible with its minor line;
- a minor release may make a documented breaking change;
- all eight crates still advance together, even when only one crate changes; and
- adapter manifests use an exact requirement for
hubuum-storage-coreand the matchinghubuum-storage-conformancerelease.
At 1.0.0, ordinary Semantic Versioning applies: compatible additions use a
minor release, fixes use a patch release, and incompatible changes use a major
release.
StorageBackend is the mandatory aggregate. Adding a required supertrait or
trait method, removing or changing a method, changing a carrier or result, or
changing a closed semantic vocabulary is incompatible for adapter authors. It
therefore requires a coordinated minor release before 1.0.0 and a major
release afterward. The project will not hide a required capability behind an
unsupported default. A versioned parallel aggregate is introduced only if a
future migration genuinely requires two application contract generations to
coexist; it is not the routine evolution mechanism.
cargo-semver-checks runs against the latest crates.io release for every SDK
crate. Its result supplements the policy above: a change that is behaviorally
breaking still requires the coordinated incompatible release even if a source
API checker cannot detect it.
MSRV and Features¶
The minimum supported Rust version is Rust 1.88 for the entire release train.
Every documented feature combination must build and be usable on that version.
Raising the MSRV requires an incompatible coordinated release and migration
notice during 0.x; after 1.0.0, it follows the project's documented major
release policy unless a future policy explicitly establishes an MSRV window.
The two optional features are additive:
hubuum-domain/openapiadds Utoipa schema implementations; andhubuum-events-core/schemaadds Utoipa schema implementations and enableshubuum-domain/openapi.
Default behavior must not change when either feature is disabled. Removing or renaming a feature, making it mandatory, or changing a feature so it removes an API is incompatible. New additive features are compatible when existing feature combinations keep their behavior.
Enum Evolution¶
Public SDK enums have an explicit closed or extensible policy.
hubuum-storage-core::StorageCapability is extensible and carries
#[non_exhaustive]. Downstream diagnostics must include a wildcard match arm;
new capability labels are compatible additions.
Every other public SDK enum is a closed semantic vocabulary. Adding, removing, renaming, or reinterpreting a variant is an incompatible change. The audited closed set is:
hubuum-computed-fields:DefinitionError,FieldErrorCode,Operation, andResultType;hubuum-domain:EventDeliveryStatus,JsonPatchErrorKind,JsonSchemaErrorKind,MaintenanceState,PrincipalKind,ResourceRevisionError, andStorageJsonValidationError;hubuum-schema-diagnostics:SchemaActualValue,SchemaDiagnosticInspection,SchemaDiagnosticOmission, andSchemaExpectedValue;hubuum-events-core:Action,ActorKind,EntityType,EventCatalogError,EventFilterError, andEventSinkSecretError;hubuum-query:ComputedFieldScope,ComputedQueryValueType,CursorCodecError,CursorValue,DataType,Operator,QueryError,QueryScalarType,RelatedClassField,RelatedFilterTarget,RelatedObjectField,SearchOperator,StructuredQueryExpression, andStructuredQueryField;hubuum-task-core:IdempotencyKeyError,TaskControlError, andTaskStopReason; andhubuum-storage-core: all public enums exceptStorageCapability, including authorization permissions, errors, lifecycle selectors, query dimensions, task and restore states, import policies, mutation outcomes, notifications, and execution call sites.
Error enums are deliberately closed because their classifications are part of the portable contract. A new failure category requires adapter and caller review rather than being silently absorbed by a wildcard. Private adapter enums and application HTTP enums are outside this SDK policy.
Deprecation and Removal¶
A supported item is normally deprecated for at least one coordinated minor release before removal. Removal occurs only in an incompatible release and the changelog gives the replacement and migration action. A required aggregate method is not deprecated until its replacement can express the complete semantics and the conformance suite covers the migration.
An urgent security or soundness problem may require immediate removal or restriction. That release must contain an explicit security note, affected versions, and the safest available migration.
Release Process¶
SDK releases are distinct from server vX.Y.Z releases. Maintainers:
- choose one version for all eight packages and update every exact in-graph
dependency plus
Cargo.lock; - record supported additions, changes, deprecations, and every breaking
migration in
CHANGELOG.md; - update the crate policy documents, storage contract, method registry, semantic evidence, and conformance behavior together;
- run the Rust API policy, package, rustdoc, SemVer, formatting, lint, and full repository suites;
- publish in dependency order, waiting for crates.io index visibility between
layers:
hubuum-computed-fields,hubuum-domain,hubuum-query, andhubuum-task-corefirst,hubuum-events-coresecond,hubuum-storage-corethird, andhubuum-storage-conformancelast; and - create an annotated
storage-sdk-vX.Y.Ztag and release notes only after all seven immutable crate versions are visible.
The local publication checks are:
python3 scripts/check-rust-api-policy.py
python3 tests/python/run.py unit policies.test_rust_api
cargo package --locked \
--package hubuum-computed-fields \
--package hubuum-domain \
--package hubuum-events-core \
--package hubuum-query \
--package hubuum-task-core \
--package hubuum-storage-core \
--package hubuum-storage-conformance
CI builds rustdoc with warnings denied and all features enabled. It runs
cargo-semver-checks once a registry baseline exists. Publication itself is a
maintainer-controlled operation because crates.io versions cannot be replaced.
Adapter Upgrade Process¶
Adapter authors should upgrade hubuum-storage-core and
hubuum-storage-conformance to the same exact SDK version, update every direct
SDK dependency to that version, and then:
- compile the complete
StorageBackendaggregate; - run the unchanged portable conformance suite;
- run backend-native transaction, consistency, migration, failure, and connection-loss tests; and
- review the SDK changelog for behavior changes that compile-time checks do not express.
An adapter version supports exactly the SDK version it declares. Applications select adapters statically and do not negotiate compatibility at runtime.
Data, Errors, Runtime, and Security¶
Crate-specific policy documents under docs/rust_api/ define supported
entrypoints, error and panic behavior, runtime and cancellation expectations,
serialization guarantees, and secret-redaction requirements. The
storage contract,
query semantics, and
testing contract are normative for adapter
behavior.
Upgrading from 0.1 to 0.2¶
Update all seven SDK dependencies together. Relation query constructors now
require TraversalBudget; adapters must enforce its depth and generated-work
limits before final sorting and pagination. Implement the claimed import methods
with atomic domain changes and item receipts, and reject an expired or replaced
claim at commit.
The generated inventory records current package versions and minimum Rust versions. The server's configuration and deployment upgrade actions are in the runtime hardening guide.
Upgrading from 0.2 to 0.3¶
Update all SDK dependencies to exactly 0.3.0 together. Implement every required
method of the new SchemaEvolutionStorage capability in the workflow
family. Carry SchemaReference, compiled policy proof, authorized collection,
object resource revision, and task lease through the operation boundary. Publish
schema/evidence changes and their audit/outbox records atomically.
The required get_schema_work_report method returns a separate complete report
projection; get_schema_work remains a bounded cursor checkpoint.
StorageSchemaWork::record_impact now returns an optional typed finding. Append
that finding atomically with the batch checkpoint, without loading or rewriting
prior findings. Assemble reports with StorageSchemaWorkReport::builder, feeding
findings in object-ID order from the checkpoint's consistent snapshot, and call
finish to verify completeness. Preserve findings through cancellation and lease
recovery, and discard them with their work during retention or restore replacement.
Handle the closed schema_validation task kind, class_schema and
object_validation event entities, and optional StorageImportSchemaActivation
in class imports. Map the three new logical schema state sections and schema
history section for backup format 6, validate them before restore replacement,
and recreate revalidation work without restoring active leases or impact proofs.
BackupSnapshotStorage::capture_backup_snapshot now requires a validated
StorageBackupBudget in addition to the history selection. Pass deployment
limits through unchanged and enforce both logical bytes and enumerated-row work
before retaining snapshot rows. StorageBackupCaptureProgress supplies checked
accounting and content-free diagnostics. Every selectable adapter must abort on
budget exhaustion with StorageErrorKind::InputTooLarge, while preserving a
consistent snapshot and the full restore contract. Do not implement a fallback
that captures an unbounded document and checks its size afterward.
Use verify_backup_budget_rejected from hubuum-storage-conformance with
fixtures exceeding each limit, and retain native probes proving early database
or iterator termination and bounded retained state.
Run the portable conformance suite and native transaction, lease, concurrency,
and query-budget tests. The shared implementation scenarios and exact method
inventory are in docs/storage_boundary/semantic-coverage.toml; behavioral
requirements and client migration are in class schema evolution.
Schema work reporting also applies through generic task APIs. Adapters must honor
StorageTaskListQuery::excluded_kind() before totals and pagination; task initiator
attribution does not grant access to class-wide counts. Task failure must atomically
persist the schema checkpoint's terminal failed status and release its active-work
slot. Schema provenance timestamps use UTC microsecond precision across adapters.
Cancellation contract migration¶
The next incompatible SDK release adds five required TaskExecutionStorage
operations: request_task_cancellation, admit_task_execution,
poll_task_execution, acknowledge_task_stop, and begin_remote_dispatch.
Adapters must preserve private-fielded StorageTaskControl across projections
and logical backups, pin the original deadline at first admission, and honor
StorageExecutionScope::with_task_execution for actual work and cleanup.
Requests persist independently of acknowledgement. Queue withdrawal and terminal
bookkeeping are atomic. Active work keeps its live lease through cleanup, and
all terminal writes arbitrate cancellation against completion under that lease.
Strict imports fence the effect/receipt commit against the stop decision;
remote dispatch persists conservative evidence before attempting HTTP. Export
and backup artifacts are published only with their successful terminal state.
TaskCancelled and TaskDeadlineExceeded are distinct storage errors and must
not be converted into per-item import failures. Update exhaustive error/action
matches for these variants and Action::CancelRequested.
The shared application contract tests exercise every registered adapter. Keep adapter-native coverage for SQL cancellation, receipt commit races, database locking, replica recovery and connection cleanup alongside those shared tests.
Fresh credential approvals¶
The next server revision requires TokenStorage::create_credential_approval and
get_credential_approval, plus StorageRestoreConfirmation on
RestoreStorage::start_restore_draining. Identity write requests may carry a
StorageCredentialClaim; task and restore requests carry StorageCredentialUse
to preserve the claim with its event attribution. Internal login/bootstrap
issuance remains explicit and does not attach a claim.
Adapters must consume attached claims atomically with the protected write, reject
expired/replayed/mismatched claims with ReauthenticationRequired, recheck the
originating unscoped human token, and retain consumed approval metadata. A failed
mutation or event append must roll back consumption. Emit the
CredentialApproval entity's Created and Succeeded events through normal
fanout. Matching idempotent task retrieval performs no new write or consumption.
Restores preserve local approval records outside logical backup state, invalidate unused approvals, and attach consumed restore approval evidence to completion provenance. PostgreSQL and memory conformance tests cover single use, concurrency, rollback, expiry, origin revocation, and request binding. See the wire protocol and deployment guide.
Upgrading from 0.3 to 0.4¶
Update all eight SDK dependencies to exactly 0.4.0 together. Subscription
requests, projections and lookups now carry EventSubscriptionScope, which
preserves either a collection ID or system scope. Use scope().collection_id()
when an optional collection is required. TaskKind is shared through
hubuum-domain; subscription filters add task_kinds.
Implement load_event_notification, enqueue_event_notification_test and
finish_event_delivery on complete adapters. Preserve test purpose and deferral
reason, validate event scope and sink identity before preview/test, and audit
actual test requests. Atomically fence sink admission by the current unexpired
claim. Persist per-sink spacing and provider cooldown across workers. Deferrals
must leave attempts unchanged, clear claims, and honor their next attempt time;
permanent errors terminate delivery. Claim batches must allow other sinks to
make progress. Logical backups preserve delivery policy, system subscriptions
and terminal test deliveries; transient admission state resets on restore.
The built-in PostgreSQL and memory backends share application contract tests in
src/tests/storage_contract/webhook_notifications.rs; retain adapter-specific
locking and lease-loss tests when implementing these guarantees.