Orleans.Lattice.Backup API reference
This page documents Orleans.Lattice.Backup 9.9.0, in the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at api.md, and llms.txt lists every page.Every public type and member of Orleans.Lattice.Backup, grouped by role. Types not listed here are internal and are described by behaviour in Architecture.
All serializable types are Orleans-serialized ([GenerateSerializer]) with stable aliases; the constructor parameter validation noted below is enforced at construction.
Registration
LatticeBackupServiceCollectionExtensions
Static extension methods on ISiloBuilder.
| Method | Signature | Purpose |
|---|---|---|
AddLatticeBackup |
ISiloBuilder AddLatticeBackup(this ISiloBuilder builder, Action<LatticeBackupOptions>? configure = null) |
Adds the backup storage and engine surface: the default in-cluster sink, the catalog store, the capture / incremental / restore engines, the scheduler, options, and the once-per-silo history bootstrap. Ensures the view infrastructure is present so the catalog tree gets durable per-key history. Must be called after AddLattice(...); throws InvalidOperationException when called first. Idempotent. |
ConfigureLatticeBackup |
ISiloBuilder ConfigureLatticeBackup(this ISiloBuilder builder, Action<LatticeBackupOptions> configure) |
Layers an additional LatticeBackupOptions configuration delegate. |
ConfigureLatticeBackupSchedule |
ISiloBuilder ConfigureLatticeBackupSchedule(this ISiloBuilder builder, Action<LatticeBackupScheduleOptions> configure) |
Configures the global LatticeBackupScheduleOptions applied to every scope. The delegate is registered for every named instance, so it also applies to a scope that has a per-scope delegate; the delegates run in registration order, so register the global defaults first for a per-scope override to win. |
ConfigureLatticeBackupSchedule |
ISiloBuilder ConfigureLatticeBackupSchedule(this ISiloBuilder builder, string scopeKey, Action<LatticeBackupScheduleOptions> configure) |
Configures LatticeBackupScheduleOptions for a specific scope keyed by scopeKey (the value from BackupScopeKey.For). Throws ArgumentException when scopeKey is null or empty. |
ConfigureLatticeBackupHealth |
ISiloBuilder ConfigureLatticeBackupHealth(this ISiloBuilder builder, Action<LatticeBackupHealthOptions> configure) |
Configures the cluster-wide LatticeBackupHealthOptions governing the periodic backup-health monitor: whether it runs and the default re-verification cadence. Health monitoring is auto-enrolled and on by default, so this is only needed to change the cadence or disable the monitor. The monitor stays inert against a non-durable sink regardless of these options. Throws ArgumentNullException when builder or configure is null. |
Services
ILatticeBackupCaptureService
The full-capture engine.
Task<LatticeBackupCaptureResult> CaptureAsync(LatticeBackupCaptureRequest request, CancellationToken cancellationToken = default)- captures a full backup of the request's scope and returns its content-addressed id and manifest. ThrowsArgumentNullException(requestnull),LatticeAuthorizationDeniedException(unauthorized),LatticeSnapshotReplayBudgetExceededException(scope exceeds the replay budget),LatticeSaturatedException(snapshot open shed under saturation), andLatticeCursorSnapshotExpiredException(pinned snapshot expired mid-capture). With a tenancy add-on active it also throwsLatticeBackupTenantIsolationException(the tree is outside the caller's tenant) andLatticeTenantAccessDeniedException(the capture is not admitted under the calling tenant's request-rate budget).Task<LatticeBackupSetCaptureResult> CaptureSetAsync(LatticeBackupSetCaptureRequest request, CancellationToken cancellationToken = default)- captures a backup set: one full backup per scope grouped under a single set manifest. WhenCrossTreeConsistentis set and the set spans more than one tree, every tree is captured inside a single causal fence, selected after in-flight cross-tree atomic sagas drain, so a cross-tree atomic write is never torn across the set (each tree is still captured by its own snapshot, one after another). When the set spans more than one tree, every member manifest is stamped with the set'sSetId, name, and capture time (SetCreatedAtUtc) so the catalogued per-tree backups can be grouped back into one logical set entry, and the returnedBackupSetManifest.SetIdis that same id. A set of a single scope is deliberately left unstamped - it is indistinguishable from a plain backup and lists as one - so its returnedSetIdisnull: the create response agrees with the catalog row, and there is no id that resolves to nothing. Restore such a backup withRestoreAsync(backupId), notRestoreSetAsync. Throws the same exceptions asCaptureAsync, plusLatticeBackupCrossTreeFenceExceptionwhen a stable fence cannot be established within the configured attempts or drain timeout.
ILatticeBackupIncrementalCaptureService
The incremental-capture engine.
Task<LatticeBackupCaptureResult> CaptureIncrementalAsync(LatticeBackupIncrementalCaptureRequest request, CancellationToken cancellationToken = default)- captures an incremental backup layered on a base backup and records the base id as the manifest'sBaseBackupId. The base manifest is read from the sink, and the increment inherits the base's scope (the request scope is advisory). When a sound delta cannot be produced - the base resume point was trimmed off the WAL, a range delete surfaced in the delta window, or the base chain was captured on a different cluster - it falls back to a fresh full capture and returns that result instead. ThrowsArgumentNullExceptionwhenrequestis null,KeyNotFoundExceptionwhen the sink holds no manifest forBaseBackupId, andLatticeAuthorizationDeniedExceptionwhen the caller is not authorized over the base's scope, plus the tenancy exceptionsCaptureAsyncdocuments. A fallback full capture can also throw the replay-budget, saturation, and snapshot-expiry exceptionsCaptureAsyncdocuments.
ILatticeBackupRestoreService
The causally-faithful restore engine.
Task<LatticeRestoreResult> RestoreAsync(LatticeRestoreRequest request, CancellationToken cancellationToken = default)- resolves the backup's manifest (catalog first, then the sink) and authorizes the restore; only then, when the target tree is replicated, is the request handed to the coordinated restore path throughIRestoreSagaDispatcher, whose result it returns. Otherwise it walks the base chain, validates every artifact against its recorded digest, then applies the entries perLatticeRestoreRequest.Mode(in-place bulk-load / merge, or atomic shadow-cutover). Idempotent under retry. Authorization covers both trees the restore names:Restoreover the target tree, and - only whenTargetTreeIdretargets the backup onto a different tree than the one captured -Backupover the source tree recorded in each chain manifest's own scope, at the range actually replayed. A same-tree restore is unaffected. ThrowsArgumentNullException(requestnull),ArgumentException(the target is a reservedsys-backup-*tree),LatticeRestoreValidationException(pre-apply validation failure, including a backup absent from both the catalog and the sink, a broken chain, or a requested sub-scope outside the captured scope; for a replicated target, also a coordinated restore that was refused before it started or aborted), andLatticeAuthorizationDeniedException(unauthorized). With a tenancy add-on active it also throwsLatticeBackupTenantIsolationExceptionwhen the target tree, or a retargeted source tree, is outside the caller's tenant. AShadowCutoverrestore also throwsInvalidOperationExceptionwhen the target tree is deleted, a delete of it is pending, or another alias change of it (a resize, a schema remediation, or a different restore or revert) holds its alias reservation, andLatticeTreeOwnershipDeniedExceptionwhen the registered tree ownership guard refuses its alias swap; see Architecture.Task<IReadOnlyList<LatticeRestoreResult>> RestoreSetAsync(string setId, CancellationToken cancellationToken = default)- expands a captured backup set into its member trees (by scanning the catalog for the manifests stamped withsetId), authorizesRestoreover every member tree before anything is dispatched, and restores each one via shadow-cutover, promoting to a single all-or-nothing coordinated saga when any member is replicated. A set naming one tree the caller may not restore is therefore refused whole withLatticeAuthorizationDeniedException(or, with a tenancy add-on active,LatticeBackupTenantIsolationException). ThrowsArgumentExceptionwhensetIdis null or empty, or when it resolves to no member trees. That last failure distinguishes its two causes: an id that equals the set id a single catalogued backup would have been given (the content address of that one member id) names a single-tree set, which is captured as a plain backup and is never stamped as a set member, so the message names the exactbackupIdto pass toRestoreAsyncinstead; any other unresolved id is reported as absent from the catalog. A local per-member restore can also fail with the exceptionsRestoreAsyncdocuments for aShadowCutoverrestore.Task RevertRestoreAsync(LatticeRestoreResult restore, CancellationToken cancellationToken = default)- reverts aShadowCutoverrestore by swapping the target tree's registry alias back toPreviousPhysicalTreeId. Idempotent. Authorization gates the logical target tree, so the physical tree ids onrestoreare separately re-validated against registry provenance: each must be the target itself, a shadow the engine built for that target, or the target's current physical tree. ThrowsArgumentNullException(restorenull),ArgumentException(not a shadow-cutover result),LatticeRestoreValidationException(a named physical tree does not belong to the target), andLatticeAuthorizationDeniedException(unauthorized). Also throwsInvalidOperationExceptionwhile the tree is deleted, a delete of it is pending, or another alias change holds its alias reservation, andLatticeTreeOwnershipDeniedExceptionwhen the registered tree ownership guard refuses re-pointing the alias.
ILatticeBackupScheduler
The public entry point for on-demand triggers, schedule registration, and retention. Each operation targets a BackupScopeSelector and is coordinated per scope so triggers, scheduled captures, and retention for the same scope never overlap.
Task<string?> TriggerFullBackupAsync(BackupScopeSelector scope)- triggers a full backup; returns the backup id, ornullwhen a capture for the scope is already in flight.Task<string?> TriggerIncrementalBackupAsync(BackupScopeSelector scope)- triggers an incremental backup layered on the most recent backup for the scope (or a full baseline when none exists); returns the backup id, ornullwhen skipped by the overlap guard.Task ScheduleRecurringBackupAsync(LatticeBackupScheduleRequest request)- registers or updates a recurring backup of the request's scope that fires everyInterval, capturing a full or incremental backup per the request. The interval is clamped up to the reminder minimum; a runtime schedule registered this way overrides the configuredLatticeBackupScheduleOptionscadence for the chosen kind. Idempotent. Authorizes the caller'sBackupcapability over the scope at registration (the reminder-fired cycle later runs system-origin, because a reminder carries no caller). ThrowsArgumentNullExceptionwhenrequestis null andLatticeAuthorizationDeniedExceptionwhen the caller is not authorized.Task CancelScheduleAsync(BackupScopeSelector scope, bool incremental)- removes the scope's recurring schedule for one kind (incrementalselects the incremental schedule, otherwise the full one): unregisters that kind's schedule reminder and clears any runtime interval override. Idempotent: a missing schedule is a no-op.Task EnsureScheduleAsync(BackupScopeSelector scope)- registers or updates the recurring full and incremental schedule reminders for the scope per itsLatticeBackupScheduleOptions: an enabled kind is (re-)registered at its configured cadence and a disabled kind's reminder is unregistered. It consults only the configured options, so running it afterScheduleRecurringBackupAsyncreplaces (or, for a kind disabled in options, removes) that kind's runtime schedule reminder; the runtime interval that call recorded is left in place, soBackupSchedulerRuntimeStatuskeeps reporting it untilCancelScheduleAsyncclears it. Idempotent. Authorizes the caller'sBackupcapability over the scope and throwsLatticeAuthorizationDeniedExceptionwhen it is not granted.Task<BackupRetentionReport> PruneAsync(BackupScopeSelector scope)- prunes the scope's backup chain per its retention policy, preserving the base chain of every retained increment; a no-op that retains everything when retention is disabled.
All five scope-typed methods throw ArgumentNullException when scope is null. The two triggers are authorized by the capture engine they run, and ScheduleRecurringBackupAsync and EnsureScheduleAsync authorize at registration; CancelScheduleAsync and PruneAsync perform no authorization check of their own.
ILatticeBackupCatalogStore
The durable, introspectable index of manifests, persisted into the reserved sys-backup-catalog tree keyed by backup id.
Task RegisterAsync(BackupManifest manifest, CancellationToken cancellationToken = default)- registers or replaces a manifest, keyed bymanifest.Id. Re-registering an id that is already catalogued carries the existing row'sCreatedAtUtcforward (a backup id is a content address, so the capture time is immutable); every other field, set membership included, takes the incoming manifest's value. Idempotent. ThrowsArgumentNullExceptionwhenmanifestis null.Task<BackupManifest?> GetAsync(string backupId, CancellationToken cancellationToken = default)- reads a manifest, ornull. ThrowsArgumentExceptionwhenbackupIdis null or empty.Task<bool> RemoveAsync(string backupId, CancellationToken cancellationToken = default)- removes a manifest; returnstruewhen one was removed. ThrowsArgumentExceptionwhenbackupIdis null or empty.IAsyncEnumerable<BackupManifest> ListAsync(CancellationToken cancellationToken = default)- enumerates every catalogued manifest in backup-id order.
ILatticeBackupSink
The pluggable storage sink a backup is written to and restored from. Stores streamed artifacts and self-describing manifests; the artifact surface moves the payload as an ordered chunk sequence so a large tree streams without being materialized whole. Re-writing the same artifact id with the same content is idempotent. The capture engine names each artifact with a per-capture id (scope tree id, scope kind, capture ticks, and a GUID) and records the artifact's SHA-256 digest (BackupContentHash) in the manifest's content descriptor; the content-addressed id is the backup (manifest) id, not the artifact id.
Capability members:
bool IsDurable- whether the sink stores payload outside the cluster it protects (an external, durable store such as Azure Blob or the filesystem sample sink), as opposed to the ephemeral in-cluster sink whose payload shares the fate of the cluster. Disaster-recovery features that only make sense against an off-cluster store - notably the periodic backup-health monitor - gate themselves on this flag:falsekeeps the monitor inert and hides the Explorer health column.
Artifact members:
Task WriteArtifactAsync(string artifactId, IAsyncEnumerable<ReadOnlyMemory<byte>> content, CancellationToken cancellationToken = default)- writes an artifact as an ordered chunk stream. Idempotent for the same id and content. ThrowsArgumentException(artifactIdnull/empty) andArgumentNullException(contentnull).IAsyncEnumerable<ReadOnlyMemory<byte>> ReadArtifactAsync(string artifactId, CancellationToken cancellationToken = default)- reads an artifact back as an ordered chunk stream; yields nothing when absent. ThrowsArgumentExceptionwhenartifactIdis null or empty.Task<bool> DeleteArtifactAsync(string artifactId, CancellationToken cancellationToken = default)- removes an artifact; returnstruewhen one was removed. ThrowsArgumentExceptionwhenartifactIdis null or empty.IAsyncEnumerable<string> ListArtifactIdsAsync(CancellationToken cancellationToken = default)- enumerates every artifact id in id order.
Manifest members:
Task WriteManifestAsync(BackupManifest manifest, CancellationToken cancellationToken = default)- creates or replaces a manifest keyed bymanifest.Id. Idempotent. ThrowsArgumentNullExceptionwhenmanifestis null.Task<BackupManifest?> ReadManifestAsync(string backupId, CancellationToken cancellationToken = default)- reads a manifest, ornull. ThrowsArgumentExceptionwhenbackupIdis null or empty.IAsyncEnumerable<BackupManifest> ListManifestsAsync(CancellationToken cancellationToken = default)- enumerates every manifest in backup-id order.Task<bool> DeleteManifestAsync(string backupId, CancellationToken cancellationToken = default)- removes a manifest; returnstruewhen one was removed. Does not remove referenced artifacts. ThrowsArgumentExceptionwhenbackupIdis null or empty.
Sink-existence probe members (read-only, cheap - existence and committed-metadata only, never downloading or hashing payload):
Task<bool> ManifestExistsAsync(string backupId, CancellationToken cancellationToken = default)- the cheap liveness check used at selection time:truewhen the manifest is present in the sink. ThrowsArgumentExceptionwhenbackupIdis null or empty.Task<BackupSinkResolution> ProbeAsync(string backupId, CancellationToken cancellationToken = default)- the richer resolvability probe used by reconcile / scrub: reports whether the manifest is present and which referenced artifacts are missing (absent, or - for sinks that mark commit - present but not committed). ThrowsArgumentExceptionwhenbackupIdis null or empty.
ILatticeBackupCatalogScrubService
Reconciles the in-cluster catalog against the durable sink in the opposite direction to the rebuild service: it finds catalog rows the sink can no longer resolve (orphans) rather than sink manifests the catalog is missing.
Task<BackupCatalogScrubReport> ScrubAsync(bool pruneOrphans = false, CancellationToken cancellationToken = default)- enumerates every catalog row and probes the sink (ILatticeBackupSink.ProbeAsync) for its resolvability, collecting the orphans - rows whose sink payload (manifest, or a referenced artifact) is gone. Non-destructive by default: it only flags orphans. WhenpruneOrphansistrueit removes each orphan catalog row under system origin, which is idempotent on re-run (a pruned orphan is no longer scanned). Returns aBackupCatalogScrubReportsummarizing counts scanned, orphaned, and removed, whether pruning ran, and the orphan backup ids.
ILatticeBackupCatalogRebuildService
Rebuilds the in-cluster catalog from the durable sink, treating the sink as the single source of truth and the catalog as a rebuildable, self-healing projection over it.
Task<BackupCatalogRebuildReport> RebuildFromSinkAsync(CancellationToken cancellationToken = default)- scans every manifest the sink holds (viaILatticeBackupSink.ListManifestsAsync) and re-registers each into the catalog under system-origin. Idempotent and safe to re-run: a manifest already catalogued is reconciled in place (keeping its immutable capture timestamp) rather than duplicated, and a catalog missing rows the sink has is repopulated. Returns aBackupCatalogRebuildReportsummarizing counts scanned, freshly added, and reconciled.
ILatticeBackupColdRestoreService
Restores a backup into a fresh cluster from the durable sink alone, with zero dependency on any surviving sys-backup-catalog tree. This is the disaster-recovery entry point: a cluster that lost its grain storage (so its catalog is gone) but still has the external sink can enumerate, resolve, chain-walk, and restore its backups from the sink.
Task<LatticeRestoreResult> ColdRestoreAsync(LatticeRestoreRequest request, CancellationToken cancellationToken = default)- bootstraps the reservedsys-trees if they are absent, resolves the target (tip) manifest from the sink alone (never the catalog), then hands the request to the ordinary restore engine (ILatticeBackupRestoreService.RestoreAsync), which walks theBaseBackupIdchain catalog-first with a sink fallback - so on a cluster that lost its catalog the whole chain resolves from the sink - validates every referenced artifact, read from the sink, against its recorded digest, and replays the chain through the HLC-preserving seams; it then re-projects the catalog from the sink so the recovered cluster is left with a correct catalog. ReusesLatticeRestoreRequest/LatticeRestoreResult. Idempotent. ThrowsLatticeRestoreValidationExceptionwhen the backup is absent from the sink, the base chain is broken, or an artifact is missing or tampered;LatticeAuthorizationDeniedExceptionwhen the caller is not authorized (the delegated restore authorizes exactly asRestoreAsyncdoes); andArgumentNullExceptionwhenrequestis null. The delegated restore can also throw the other exceptionsRestoreAsyncdocuments.
ILatticeBackupHealthService
Verifies that a backup's durable sink payload is present and intact, layering content-hash verification on top of the cheap presence probe. Registered by AddLatticeBackup.
Task<BackupHealthReport> VerifyAsync(string backupId, CancellationToken cancellationToken = default)- resolves the backup's manifest, checks presence and committed-metadata of every referenced artifact (reusingILatticeBackupSink.ProbeAsync), then downloads each present artifact and re-hashes it against its recordedBackupContentDescriptor.ContentHashto catch silent corruption. Returns a fresh point-in-timeBackupHealthReport; does not persist it. ThrowsArgumentExceptionwhenbackupIdis null or empty.
ILatticeBackupHealthStore
Persists per-backup health state - the latest BackupHealthReport and the per-backup BackupHealthConfig - in the reserved sys-backup-health ILattice tree keyed by backup id, so the periodic monitor that writes reports and the UI that reads them share one durable projection (no second external store). Registered by AddLatticeBackup.
Task SetReportAsync(BackupHealthReport report, CancellationToken cancellationToken = default)- persists (or replaces) the latest report for itsBackupId. ThrowsArgumentNullExceptionwhenreportis null.Task<BackupHealthReport?> GetReportAsync(string backupId, CancellationToken cancellationToken = default)- reads the latest report, ornull. ThrowsArgumentExceptionwhenbackupIdis null or empty.IAsyncEnumerable<BackupHealthReport> ListReportsAsync(CancellationToken cancellationToken = default)- enumerates every stored report in backup-id order.Task<bool> RemoveAsync(string backupId, CancellationToken cancellationToken = default)- removes the stored report and configuration for a backup; returnstruewhen anything was removed. ThrowsArgumentExceptionwhenbackupIdis null or empty.Task SetConfigAsync(string backupId, BackupHealthConfig config, CancellationToken cancellationToken = default)- persists (or replaces) the per-backup monitor configuration. ThrowsArgumentException(backupIdnull/empty) andArgumentNullException(confignull).Task<BackupHealthConfig?> GetConfigAsync(string backupId, CancellationToken cancellationToken = default)- reads the per-backup configuration, ornullwhen the backup uses the configured defaults. ThrowsArgumentExceptionwhenbackupIdis null or empty.
The periodic monitor itself is an internal reminder-driven grain (mirroring the backup scheduler): once per sweep it enumerates the catalog and re-verifies each enrolled backup whose configured interval has elapsed, writing the result through ILatticeBackupHealthStore. It is inert unless the registered sink reports IsDurable and LatticeBackupHealthOptions.Enabled is true.
Extension seams (replication-aware backup)
These backup-package-local seams let the replication package layer replication awareness on top of the backup engine - an atomic multi-tree, multi-cluster restore, and a capture-side check that the sink is actually shared - without the backup package taking a dependency on replication. The dispatch, membership, and probe seams (IRestoreSagaDispatcher, IReplicatedTreeMembership, IBackupSinkSharingProbe) each have a default no-op registration installed by AddLatticeBackup, so a single-cluster host always takes the plain local restore path and never runs a cross-cluster probe; the replication package (or the host) supplies the real implementation. ILatticeCoordinatedRestoreEngine and ILatticeBackupSetResolver run the other way: AddLatticeBackup registers their real implementations (the restore engine itself, and a resolver that scans the catalog for set-stamped manifests), and the replication package consumes them.
IRestoreSagaDispatcher
The seam the restore path consults so a restore into a replicated tree can be promoted to an all-or-nothing coordinated restore across every cluster that replicates the target. The decision is a function of the target tree's current replication status, never of the backup's origin. RestoreAsync and RestoreSetAsync consult it only after they have authorized the restore, so the coordinated path never runs for a caller the restore gate refuses. The default registration never dispatches.
Task<LatticeRestoreResult?> TryDispatchAsync(LatticeRestoreRequest request, CancellationToken cancellationToken = default)- offers a single-tree restore to the coordinated path; returns the local cluster's result when the coordinated path handled it, ornullto signal the caller should run the plain local restore. ThrowsArgumentNullExceptionwhenrequestis null.Task<IReadOnlyList<LatticeRestoreResult>?> TryDispatchSetAsync(string setId, LatticeRestoreMode mode, CancellationToken cancellationToken = default)- offers a backup-set restore as one atomic unit over the union of the replicated members' peer sets; returns this cluster's per-member results, ornullwhen no member is replicated (or the id is not a set id). ThrowsArgumentExceptionwhensetIdis null or empty.
IReplicatedTreeMembership
The seam the startup sink guard consults to learn whether a tree participates in the cross-cluster replication set (a replicated tree must be backed by a shared external sink, not the default in-cluster sink). The default registration reports nothing replicated.
bool IsReplicated(string treeId)- reports whether the tree participates in the replication set. ThrowsArgumentNullExceptionwhentreeIdis null.IReadOnlyCollection<string> ReplicatedTrees { get; }- the ids of every replicated tree.
IBackupSinkSharingProbe
The capture-side analogue of IRestoreSagaDispatcher: the seam the startup sink guard and the periodic health monitor consult to learn whether the sink this cluster captures into is demonstrably the same store every peer cluster reads from. That is a deployment fact rather than a locally provable configuration property - two regions can hold identical-looking connection strings that resolve to different accounts - so the real (replication-supplied) implementation writes a tiny marker naming this cluster into its own sink and reads every peer's marker back out of that same sink. The default registration never probes and always reports NotApplicable.
BackupSinkSharingReport? LastReport { get; }- the most recent verdict, ornullwhen the probe has never run. Read by the per-backup health path so annotating a report costs no I/O.Task<BackupSinkSharingReport> ProbeAsync(CancellationToken cancellationToken = default)- runs the probe now and publishes the fresh verdict toLastReport. Inert (no sink or network I/O, verdictNotApplicable) when no tree is replicated or the deployment has no peers.
BackupSinkSharingReport
The outcome of one cross-cluster sharing probe. Serialized (alias olb.sh), immutable.
- Constructor:
BackupSinkSharingReport(BackupSinkSharingStatus status, string clusterId, int peerCount, IReadOnlyList<string> unconfirmedPeerClusterIds, DateTimeOffset probedAtUtc, string explanation). ThrowsArgumentNullException(clusterId,unconfirmedPeerClusterIds, orexplanationnull) andArgumentOutOfRangeException(peerCountnegative). BackupSinkSharingStatus Status- the verdict.string ClusterId- the local cluster's id, as attested by the marker it wrote.int PeerCount- the number of peer clusters considered.IReadOnlyList<string> UnconfirmedPeerClusterIds- the peers whose marker could not be read back from this cluster's sink.DateTimeOffset ProbedAtUtc- when the probe ran.string Explanation- an operator-facing sentence naming the unconfirmed peers and the remediation.bool IsRefuted-trueonly whenStatusisNotShared.
BackupSinkSharingStatus
| Value | Meaning |
|---|---|
NotApplicable |
Nothing was measured: no replicated tree, no peers, no replication package, or the probe is disabled. The value a single-cluster deployment always reports. |
Shared |
Every peer's marker was read back from this cluster's sink, so a coordinated restore can resolve the same backup fleet-wide. |
Unverified |
At least one peer left no marker and was not reachable, so it may simply not be running yet. Undecided, not a fault. |
NotShared |
At least one peer is reachable yet its marker is absent, so the sink is not shared and backups of a replicated tree are not restorable fleet-wide. |
ILatticeCoordinatedRestoreEngine
Decomposes the atomic ShadowCutover restore into the separate phases a coordinated restore saga drives independently. The single ILatticeBackupRestoreService.RestoreAsync entry point composes these same phases for the local path, so both paths share one alias swap. Saga-unaware: it exposes the mechanism without any knowledge of the coordinator, write fence, or participant model.
Task<RestoreAdmissionReport> ProbeAdmissionAsync(LatticeRestoreRequest request, CancellationToken cancellationToken = default)- resolves the target's manifest, authorizesRestoreover the effective restore scope (the same target-side checkBuildShadowAsyncmakes), then walks the manifest chain and reports its size and topology without validating artifacts, fencing, or building, so an infeasible target is refused up front. ThrowsArgumentNullException(requestnull),LatticeRestoreValidationException(the backup or a chain member is missing, or a requested sub-scope falls outside the captured scope), andLatticeAuthorizationDeniedException(unauthorized).Task<LatticeRestoreResult> BuildShadowAsync(LatticeRestoreRequest request, CancellationToken cancellationToken = default)- builds the shadow tree from the manifest chain into a fresh physical tree without swapping the alias or fencing the live tree. Idempotent and resumable. Authorizes both trees exactly asRestoreAsyncdoes. Registering the shadow takes the target tree's alias reservation, which a commit or a garbage-collect of the shadow releases. ThrowsArgumentNullException(requestnull),ArgumentException(not a shadow-cutover request, or a reservedsys-backup-*target),LatticeRestoreValidationException(validation failure),LatticeAuthorizationDeniedException(unauthorized), andInvalidOperationException(the target tree is deleted, a delete of it is pending, or another alias change holds its reservation).Task CommitShadowAsync(LatticeRestoreResult shadow, CancellationToken cancellationToken = default)- commits a built shadow by atomically swapping the registry alias, then refreshing routing and converging any covering tag index. The caller engages the write fence around this call. Idempotent. AuthorizesRestoreover the whole target tree. The physical tree ids carried onshadoware re-validated against registry provenance, so a result whoseShadowPhysicalTreeIdorPreviousPhysicalTreeIdnames a tree that is neither the target, nor a shadow the engine built for that target, nor the target's current physical tree is refused. Releases the target tree's alias reservation once the cutover completes. ThrowsArgumentNullException(shadownull),ArgumentException(not a shadow-cutover build result),LatticeRestoreValidationException(a named physical tree does not belong to the target),LatticeAuthorizationDeniedException(unauthorized),InvalidOperationException(the target tree is deleted, a delete of it is pending, or a different alias change holds its reservation), andLatticeTreeOwnershipDeniedException(the registered tree ownership guard refuses the alias swap).Task DeleteShadowAsync(string shadowPhysicalTreeId, CancellationToken cancellationToken = default)- reliably garbage-collects an orphaned shadow so an aborted restore leaks no storage. Idempotent: a tree that was never registered is a no-op. Because it purges every shard of the named tree, it deletes only a tree the engine itself stamped as a restore shadow, and authorizesRestoreover the logical tree that shadow was built for - taken from the shadow's own registry provenance, never from the argument. It also releases the alias reservation the shadow build took on that logical tree, so an aborted restore does not go on refusing the tree's delete or later alias changes. ThrowsArgumentExceptionwhenshadowPhysicalTreeIdis null or empty,LatticeRestoreValidationExceptionwhen the named tree is registered but is not a restore shadow, andLatticeAuthorizationDeniedException(unauthorized).string ResolveShadowTreeId(LatticeRestoreRequest request)- deterministically resolves the shadow tree id a build ofrequestwould produce, without I/O, so an aborting participant can garbage-collect by id after losing its in-memory state. ThrowsArgumentNullException(requestnull) andArgumentException(no explicit target tree).
ILatticeBackupSetResolver
The saga-unaware read seam that expands a captured backup-set id into the per-tree member backups it references, so the restore path can restore every tree in a set as one unit.
Task<IReadOnlyList<BackupSetMember>> ResolveMembersAsync(string setId, CancellationToken cancellationToken = default)- resolves the set's member backups in tree-id order, or an empty list when the id is not a set id (for example a single-tree backup id). ThrowsArgumentExceptionwhensetIdis null or empty.
BackupSetMember
One resolved member of a captured backup set: the member backup id and the tree it restores. Returned by ILatticeBackupSetResolver. An in-process value only (no serializer surface).
string BackupId- the content-addressed id of the member backup.string TreeId- the tree the member backup restores.
Tenancy seam
The seam the backup engine consults to keep every capture and restore inside the active tenant's t/{tenantId}/{name} namespace and within the tenant's quota. It follows the same null-default pattern as the data-plane tenant gate: AddLatticeBackup installs an inert internal implementation (IsActive is false, every check a no-op), so a host without a tenancy add-on is unchanged; the tenancy add-on registers the active implementation in its place. The tenant is the ambient active tenant, not a parameter.
ILatticeBackupTenantScope
bool IsActive { get; }-truewhen a tenancy add-on has replaced the null default; every tenant check is gated on it.void AuthorizeCapture(string treeId)- verifies the active tenant may capturetreeId: a platform tree is left to the authorization gate, and a tenant-owned tree may be captured only by its owning tenant (a flow with no active tenant is likewise left to the authorization gate). ThrowsLatticeBackupTenantIsolationExceptionwhen refused.void AuthorizeRestoreTarget(string treeId)- applies the same ownership rule to a restore target, before any record is streamed. ThrowsLatticeBackupTenantIsolationExceptionwhen refused.ValueTask<IBackupRestoreAdmission> BeginRestoreAsync(string targetTreeId, CancellationToken cancellationToken = default)- opens a per-record admission controller for a restore intotargetTreeId, resolving the active tenant's quota once.
IBackupRestoreAdmission
The per-restore admission controller the restore stream consults once per record. A refused record is dead-lettered (skipped), never silently written. Not required to be thread-safe.
long AdmittedCount { get; }- records admitted (written) so far.long DeadLetteredCrossTenant { get; }- records dead-lettered because they were addressed outside the active tenant's namespace.long DeadLetteredOverQuota { get; }- records dead-lettered because admitting them would exceed the active tenant's key quota.BackupRestoreRecordDisposition Admit(string key)- decides whether the record may be written, updating the counters. ThrowsArgumentNullExceptionwhenkeyis null.
BackupRestoreRecordDisposition
| Value | Meaning |
|---|---|
Admit |
Inside the active tenant's namespace and within quota; the record is written. |
CrossTenant |
Addressed outside the active tenant's namespace; the record is dead-lettered. |
OverQuota |
Would take the active tenant past its key quota; the record is dead-lettered. |
An in-process control value only (no serializer surface).
Operation constants and helpers
BackupOperationKinds
Public constants for tracked backup operation kinds. Prefix is backup., and the concrete kinds are Capture (backup.capture), IncrementalCapture (backup.incremental-capture), SetCapture (backup.set-capture), Restore (backup.restore), and ColdRestore (backup.cold-restore).
BackupOperationPhases
Public constants for progress phases reported by tracked operations: Capturing, CapturingMembers, Cataloguing, Bootstrapping, Validating, Applying, and Replaying. A kind reports only the phases that apply to the work in hand.
BackupOperationUnits
Public constants for progress unit names: Entries (entries), Shards (shards), Members (members), and Manifests (manifests).
BackupOperationResultKeys
Public constants for the string result map carried by a succeeded tracked operation: backupId, setId, memberBackupIds, targetTreeId, mode, restoreOperationId, manifestChain, entriesApplied, shadowPhysicalTreeId, previousPhysicalTreeId, deadLetteredCrossTenant, and deadLetteredOverQuota.
BackupOperationResults
Helpers for reading operation result maps. TryReadRestoreResult(IReadOnlyDictionary<string, string> result, out LatticeRestoreResult? restore) reconstructs the full restore result when the map has the restore keys, and ReadMemberBackupIds(IReadOnlyDictionary<string, string> result) parses the comma-separated set-member backup ids.
Requests and results
LatticeBackupCaptureRequest
Full-capture request.
const int DefaultPageSize = 1024.- Constructor:
LatticeBackupCaptureRequest(string name, BackupScopeSelector scope, int pageSize = DefaultPageSize). ThrowsArgumentException(namenull/empty),ArgumentNullException(scopenull),ArgumentOutOfRangeException(pageSizenot positive). - Properties:
string Name,BackupScopeSelector Scope,int PageSize.
LatticeBackupIncrementalCaptureRequest
Incremental-capture request.
- Constructor:
LatticeBackupIncrementalCaptureRequest(string name, BackupScopeSelector scope, string baseBackupId, int pageSize = LatticeBackupCaptureRequest.DefaultPageSize). ThrowsArgumentException(nameorbaseBackupIdnull/empty),ArgumentNullException(scopenull),ArgumentOutOfRangeException(pageSizenot positive). - Properties:
string Name,BackupScopeSelector Scope,string BaseBackupId,int PageSize.
LatticeBackupCaptureResult
- Constructor:
LatticeBackupCaptureResult(string backupId, BackupManifest manifest). ThrowsArgumentException(backupIdnull/empty) andArgumentNullException(manifestnull). - Properties:
string BackupId,BackupManifest Manifest.
LatticeBackupSetCaptureRequest
Backup-set request.
- Constructor:
LatticeBackupSetCaptureRequest(string name, IReadOnlyList<BackupScopeSelector> scopes, bool crossTreeConsistent = false, int pageSize = LatticeBackupCaptureRequest.DefaultPageSize). ThrowsArgumentExceptionwhennameis null/empty,scopesis empty, or two scopes name the same tree;ArgumentNullExceptionwhenscopesor a member is null;ArgumentOutOfRangeExceptionwhenpageSizeis not positive. - Properties:
string Name,IReadOnlyList<BackupScopeSelector> Scopes,bool CrossTreeConsistent,int PageSize.
LatticeBackupSetCaptureResult
- Constructor:
LatticeBackupSetCaptureResult(BackupSetManifest setManifest, IReadOnlyList<LatticeBackupCaptureResult> members). ThrowsArgumentNullException(either null) andArgumentException(membersempty). - Properties:
BackupSetManifest SetManifest,IReadOnlyList<LatticeBackupCaptureResult> Members.
LatticeBackupScheduleRequest
A request to register a recurring backup schedule for a scope.
- Constructor:
LatticeBackupScheduleRequest(BackupScopeSelector scope, bool incremental, TimeSpan interval). ThrowsArgumentNullExceptionwhenscopeis null;ArgumentOutOfRangeExceptionwhenintervalis not strictly positive. - Properties:
BackupScopeSelector Scope,bool Incremental,TimeSpan Interval.
A runtime schedule registered from this request overrides the configured LatticeBackupScheduleOptions cadence for the chosen kind; the interval is clamped up to the scheduler minimum when smaller.
LatticeRestoreRequest
Restore request.
const int DefaultApplyBatchSize = 1024.- Constructor:
LatticeRestoreRequest(string backupId, string? targetTreeId = null, BackupScopeSelector? scope = null, LatticeRestoreMode mode = LatticeRestoreMode.InPlace, string? operationId = null, int applyBatchSize = DefaultApplyBatchSize). ThrowsArgumentException(backupIdnull/empty, ortargetTreeId/operationIdsupplied but empty) andArgumentOutOfRangeException(applyBatchSizenot positive). - Properties:
string BackupId,string? TargetTreeId,BackupScopeSelector? Scope,LatticeRestoreMode Mode,string? OperationId,int ApplyBatchSize.
LatticeRestoreResult
- Constructor:
LatticeRestoreResult(string backupId, string targetTreeId, LatticeRestoreMode mode, string operationId, IReadOnlyList<string> manifestChain, long entriesApplied, string? shadowPhysicalTreeId = null, string? previousPhysicalTreeId = null, long deadLetteredCrossTenant = 0, long deadLetteredOverQuota = 0). ThrowsArgumentException(backupId,targetTreeId, oroperationIdnull/empty),ArgumentNullException(manifestChainnull),ArgumentOutOfRangeException(entriesApplied,deadLetteredCrossTenant, ordeadLetteredOverQuotanegative). - Properties:
string BackupId,string TargetTreeId,LatticeRestoreMode Mode,string OperationId,IReadOnlyList<string> ManifestChain,long EntriesApplied,string? ShadowPhysicalTreeId,string? PreviousPhysicalTreeId,long DeadLetteredCrossTenant(records dead-lettered because they were addressed outside the active tenant's namespace), andlong DeadLetteredOverQuota(records dead-lettered because admitting them would exceed the active tenant's key quota); both are zero when no tenancy add-on is active.
Scope
BackupScopeSelector
Names a region of a tree to back up.
- Constructor:
BackupScopeSelector(BackupScopeKind kind, string treeId, string? keyOrPrefix = null). ThrowsArgumentExceptionwhentreeIdis null/empty, aWholeTreescope carries a key/prefix, or aKey/Prefixscope omits its key/prefix. - Properties:
BackupScopeKind Kind,string TreeId,string? KeyOrPrefix. - Factories:
static BackupScopeSelector WholeTree(string treeId),static BackupScopeSelector Prefix(string treeId, string prefix),static BackupScopeSelector Key(string treeId, string key).
BackupScopeKey
static string For(BackupScopeSelector scope)- the deterministic scope key used as the per-scope scheduler grain key and the named-options key. Two selectors covering the same region produce the same key. ThrowsArgumentNullExceptionwhenscopeis null.
Manifests and descriptors
BackupManifest
The self-describing record of one backup.
- Constructor:
BackupManifest(string id, string name, DateTimeOffset createdAtUtc, BackupKind kind, BackupScopeSelector scope, BackupConsistencyCut consistencyCut, BackupTopologySnapshot topology, string structuralDigest, IReadOnlyList<BackupKeyDescriptor> keyDescriptors, IReadOnlyList<BackupContentDescriptor> contentDescriptors, IReadOnlyList<BackupOriginProvenance> provenance, string? baseBackupId = null, BackupCompressionDictionaryRef? compressionDictionary = null, string? capturingClusterId = null). Validates thatidis non-empty and free of the reserved unit-separator (U+001F); thatstructuralDigestis non-empty; that anIncrementalbackup carries a non-emptybaseBackupIdand aFullbackup carries none; and null-checks the reference-type members. - Properties:
string Id,string Name,DateTimeOffset CreatedAtUtc,BackupKind Kind,BackupScopeSelector Scope,BackupConsistencyCut ConsistencyCut,BackupTopologySnapshot Topology,string StructuralDigest,IReadOnlyList<BackupKeyDescriptor> KeyDescriptors,IReadOnlyList<BackupContentDescriptor> ContentDescriptors,IReadOnlyList<BackupOriginProvenance> Provenance,string? BaseBackupId,BackupCompressionDictionaryRef? CompressionDictionary,string? SetId,string? SetName,DateTimeOffset? SetCreatedAtUtc,string? CapturingClusterId.SetId,SetName, andSetCreatedAtUtcare non-null only on a backup captured as a member of a multi-tree set: every member of one set shares the same values, so a catalog consumer can group the per-tree members into a single logical entry from a first-class fact rather than inferring it from the backup name, and the catalog index orders the members to one shared position. They are stamped when the set is captured; because re-registering a backup id replaces every field except the capture time (seeILatticeBackupCatalogStore.RegisterAsync), a later capture that reproduces a member's bytes - a standalone capture of the unchanged tree, or its capture into another set - re-registers that member with the later capture's set fields. A single-tree set leaves them null, so it lists as an ordinary backup.CapturingClusterIdnames the cluster that authored the capture (distinct from the per-entry origins inProvenance); it is stamped on every capture, an incremental inherits its base's value so a whole chain shares one stamp, andnullmarks a manifest captured before the stamp existed (read as the local cluster).
BackupConsistencyCut
The causal cut a backup was taken as of.
- Constructor:
BackupConsistencyCut(long walSequence, long hlcTimestamp, IReadOnlyDictionary<string, long>? perOriginFrontier = null, IReadOnlyDictionary<int, long>? walPartitionOffsets = null). ThrowsArgumentOutOfRangeExceptionwhenwalSequenceorhlcTimestampis negative. - Properties:
long WalSequence,long HlcTimestamp,IReadOnlyDictionary<string, long>? PerOriginFrontier,IReadOnlyDictionary<int, long>? WalPartitionOffsets(the per-partition resume offsets an incremental layers on).HlcTimestampis the wall-clock component of the highest hybrid-logical-clock stamp the capture read - over the captured entries for a full backup, over the drained delta for an incremental (never below its base's) - and0only when the capture (with its whole chain) read nothing, or for a full backup captured by a build that predates this frontier. It is also the frontier an incremental pins the WAL at while it drains forward from its base. - What a capture records besides
HlcTimestamp: a full capture setsWalSequenceto the highest next-to-assign WAL offset across the shards and partitions its snapshot covered, andWalPartitionOffsetsto the per-partition WAL heads read just before the snapshot opened. An incremental setsWalPartitionOffsetsto the per-partition frontier its drain reached andWalSequenceto the highest of those offsets.PerOriginFrontierisnullwhen the captured entries name no origin.
BackupTopologySnapshot
- Constructor:
BackupTopologySnapshot(int shardCount, int virtualShardCount, IReadOnlyList<string> shardRootDigests). ThrowsArgumentOutOfRangeExceptionwhenshardCountorvirtualShardCountis not positive,ArgumentNullExceptionwhenshardRootDigestsis null. - Properties:
int ShardCount,int VirtualShardCount,IReadOnlyList<string> ShardRootDigests. - What a capture records: all three come from the tree's routing map at the capture.
ShardCountis the number of physical shards the map names,VirtualShardCountis the map's slot count (4096 unless the tree was created with a declared virtual shard count), andShardRootDigestsholds one digest per physical shard in ascending shard-index order - the digest of the captured range on that shard, ornodigest-{index}when the tree does not maintain projection digests. The indices need not be contiguous: a shard consolidation that folds a shard away leaves a gap.
BackupKeyDescriptor
Per-key shape and merge mode.
- Constructor:
BackupKeyDescriptor(string key, BackupKeyMergeMode mergeMode, string? originId = null). ThrowsArgumentExceptionwhenkeyis null/empty. - Properties:
string Key,BackupKeyMergeMode MergeMode,string? OriginId.
BackupContentDescriptor
Describes one stored artifact.
- Constructor:
BackupContentDescriptor(string artifactId, string contentHash, long byteLength, int chunkCount, BackupScopeSelector scope). ThrowsArgumentException(artifactIdorcontentHashnull/empty),ArgumentOutOfRangeException(byteLengthorchunkCountnegative),ArgumentNullException(scopenull). - Properties:
string ArtifactId,string ContentHash,long ByteLength,int ChunkCount,BackupScopeSelector Scope.
BackupOriginProvenance
Per-origin high-water mark.
- Constructor:
BackupOriginProvenance(string originId, long highWaterSequence). ThrowsArgumentException(originIdnull/empty),ArgumentOutOfRangeException(highWaterSequencenegative). - Properties:
string OriginId,long HighWaterSequence.
BackupCompressionDictionaryRef
Reference to the compression dictionary a backup's artifacts were encoded against.
- Constructor:
BackupCompressionDictionaryRef(string dictionaryId, string digest). ThrowsArgumentExceptionwhen either is null/empty. - Properties:
string DictionaryId,string Digest.
BackupSetManifest
The record grouping a backup set's members.
- Constructor:
BackupSetManifest(string? setId, string name, DateTimeOffset createdAtUtc, bool crossTreeConsistent, BackupSetFence? fence, IReadOnlyList<string> memberBackupIds). ThrowsArgumentException(setIdempty,namenull/empty,memberBackupIdsempty),ArgumentNullException(memberBackupIdsnull). AnullsetIdis the absence of an id and is accepted; an empty one is a malformed id and is rejected. - Properties:
string? SetId,string Name,DateTimeOffset CreatedAtUtc,bool CrossTreeConsistent,BackupSetFence? Fence,IReadOnlyList<string> MemberBackupIds. SetIdis non-null only for a set spanning two or more trees. Membership is durable only as the per-memberBackupManifest.SetIdstamp, and a single-member set is deliberately left unstamped, so it reports no id rather than one that matches no catalog row. A non-nullSetIdhere therefore equals theSetIdstamped on every member's catalogued manifest when the set was captured.
BackupSetFence
The selected cross-tree causal fence of a cross-tree-consistent set.
- Constructor:
BackupSetFence(long hlcTimestamp, int drainedInFlightCount, double drainWaitMilliseconds, int attempts). ThrowsArgumentOutOfRangeExceptionwhenhlcTimestamp,drainedInFlightCount, ordrainWaitMillisecondsis negative, orattemptsis not positive. - Properties:
long HlcTimestamp(the wall-clock tick count at which the fence was selected),int DrainedInFlightCount,double DrainWaitMilliseconds,int Attempts.
Reports and status
BackupRetentionReport
- Constructor:
BackupRetentionReport(int retainedCount, IReadOnlyList<string> prunedBackupIds). ThrowsArgumentOutOfRangeException(retainedCountnegative),ArgumentNullException(prunedBackupIdsnull). - Properties:
int RetainedCount,IReadOnlyList<string> PrunedBackupIds,int PrunedCount(equalsPrunedBackupIds.Count). static BackupRetentionReport Empty- a report that retained nothing and pruned nothing.
RestoreAdmissionReport
The self-describing size and topology of a restore, resolved from the target backup's manifest chain before any fence is engaged or shadow tree is built, so a coordinated restore can hard-refuse an infeasible target up front. Returned by ILatticeCoordinatedRestoreEngine.ProbeAdmissionAsync. An in-process value only (no serializer surface).
- Constructor:
RestoreAdmissionReport(string backupId, string targetTreeId, long totalByteLength, long totalChunkCount, int shardCount, IReadOnlyList<string> manifestChain). ThrowsArgumentException(a required string null/empty),ArgumentNullException(manifestChainnull), andArgumentOutOfRangeException(totalByteLength/totalChunkCountnegative,shardCountnot positive). - Properties:
string BackupId,string TargetTreeId,long TotalByteLength,long TotalChunkCount,int ShardCount,IReadOnlyList<string> ManifestChain(base-first order).
BackupSchedulerRuntimeStatus
A scope's schedule registration and last-run status.
- Constructor:
BackupSchedulerRuntimeStatus(bool fullScheduleRegistered, bool incrementalScheduleRegistered, DateTimeOffset? lastFullRunUtc, DateTimeOffset? lastFullSuccessUtc, DateTimeOffset? lastIncrementalRunUtc, DateTimeOffset? lastIncrementalSuccessUtc, BackupScopeRunOutcome lastRunOutcome, TimeSpan? runtimeFullBackupInterval = null, TimeSpan? runtimeIncrementalBackupInterval = null). - Properties mirror the constructor parameters:
bool FullScheduleRegistered,bool IncrementalScheduleRegistered,DateTimeOffset? LastFullRunUtc,DateTimeOffset? LastFullSuccessUtc,DateTimeOffset? LastIncrementalRunUtc,DateTimeOffset? LastIncrementalSuccessUtc,BackupScopeRunOutcome LastRunOutcome,TimeSpan? RuntimeFullBackupInterval,TimeSpan? RuntimeIncrementalBackupInterval(the clamped interval of a runtime schedule registered throughScheduleRecurringBackupAsync, ornullwhen none is recorded for that kind).
BackupCatalogRebuildReport
The outcome summary of ILatticeBackupCatalogRebuildService.RebuildFromSinkAsync. ScannedCount always equals RegisteredCount + ReconciledCount.
- Constructor:
BackupCatalogRebuildReport(long scannedCount, long registeredCount, long reconciledCount). - Properties:
long ScannedCount(manifests enumerated from the sink),long RegisteredCount(absent from the catalog and freshly added),long ReconciledCount(already catalogued and reconciled in place).
BackupCatalogScrubReport
The outcome summary of ILatticeBackupCatalogScrubService.ScrubAsync. Non-destructive by default, so RemovedCount is zero and Pruned is false unless the caller opts in to pruning; a flag-only pass still reports every orphan.
- Constructor:
BackupCatalogScrubReport(long scannedCount, long orphanCount, long removedCount, bool pruned, IReadOnlyList<string> orphanBackupIds). ThrowsArgumentNullExceptionwhenorphanBackupIdsis null. - Properties:
long ScannedCount(catalog rows cross-checked against the sink),long OrphanCount(rows with no resolvable sink payload),long RemovedCount(orphan rows removed, zero on a non-destructive pass),bool Pruned(whether destructive pruning was requested for the pass -trueeven when no orphan was found),IReadOnlyList<string> OrphanBackupIds(the ids of the orphans found).
BackupSinkResolution
The read-only outcome of ILatticeBackupSink.ProbeAsync: whether a backup is resolvable from the sink alone.
- Constructor:
BackupSinkResolution(string backupId, bool manifestPresent, IReadOnlyList<string> missingArtifactIds). ThrowsArgumentException(backupIdnull/empty) andArgumentNullException(missingArtifactIdsnull). - Properties:
string BackupId,bool ManifestPresent,IReadOnlyList<string> MissingArtifactIds(referenced artifacts absent, or present but not committed), and the computedbool IsResolvable(trueonly when the manifest is present and no artifact is missing).
BackupHealthReport
The result of verifying one backup's durable sink payload - presence plus content-hash consistency, and for a replicated tree whether every peer cluster can read the sink holding it - precise enough to drive a diagnostics dialog. Persisted per backup by ILatticeBackupHealthStore.
- Constructor:
BackupHealthReport(string backupId, BackupHealthStatus status, bool manifestPresent, IReadOnlyList<string> missingArtifactIds, IReadOnlyList<string> hashMismatchArtifactIds, DateTimeOffset checkedAtUtc, string explanation, BackupSinkSharingStatus peerVisibility = BackupSinkSharingStatus.NotApplicable, IReadOnlyList<string>? peerUnconfirmedClusterIds = null). The two sharing parameters are trailing and defaulted, so every pre-existing call site and every report persisted before the probe existed still means "no cross-cluster claim made". ThrowsArgumentException(backupIdnull/empty) andArgumentNullException(missingArtifactIds,hashMismatchArtifactIds, orexplanationnull). - Properties:
string BackupId,BackupHealthStatus Status,bool ManifestPresent,IReadOnlyList<string> MissingArtifactIds(referenced artifacts absent or uncommitted),IReadOnlyList<string> HashMismatchArtifactIds(present artifacts whose content no longer matches the manifest's recorded hash),DateTimeOffset CheckedAtUtc,string Explanation(a precise human-readable summary naming the missing / mismatched artifacts and any peer that cannot see the sink),BackupSinkSharingStatus PeerVisibility,IReadOnlyList<string> PeerUnconfirmedClusterIds, and the computedbool IsHealthy(trueonly whenStatusisHealthy).
A backup of a replicated tree whose sink is positively refuted (PeerVisibility is NotShared) is reported as Warning even when it is locally intact, because a coordinated restore resolves the same manifest chain from every cluster's own sink and would abort. A non-replicated tree's report is unaffected.
BackupHealthConfig
The per-backup health-monitoring override: whether the periodic monitor verifies this backup, and how often. Every backup is auto-enrolled with the configured defaults; this record overrides that for a single backup. Persisted by ILatticeBackupHealthStore.
- Constructor:
BackupHealthConfig(bool monitoringEnabled, TimeSpan interval). ThrowsArgumentOutOfRangeExceptionwhenintervalis not strictly positive. - Properties:
bool MonitoringEnabled,TimeSpan Interval.
Catalog index
BackupCatalogIndexProjection
The ILatticeViewProjection behind the backup-catalog index materialised view (created when LatticeBackupOptions.EnableBackupCatalogIndexView is true). It lowers each catalog registration - a Set carrying a BackupManifest - into one compact BackupCatalogIndexRow, re-keyed so the index scans newest-first with the members of a backup set contiguous; deletes and range deletes project nothing, and the listing drops any index row whose backup no longer exists in the catalog.
const string Version- the projection's code-identity version (backup-catalog-index-v3).string ProjectionVersion { get; }- returnsVersion.IEnumerable<ViewWrite> Project(LatticeMutation mutation)- maps one catalog mutation to its index-row upsert.
BackupCatalogIndexRow
The compact row the index stores per catalogued backup - exactly the fields the listing filters and sorts on - so a filtered, created-descending, paged query is answered from the index and only the rows that land on the page read their full manifest. Serialized, immutable.
string BackupId,string Name,BackupKind Kind,string TreeId,DateTimeOffset CreatedAtUtc- the indexed backup's id, name, kind, scope tree, and capture time.string? SetId,string? SetName- the backup set the backup belongs to, ornullwhen it was captured standalone.string? BaseBackupId- the base an incremental is layered on, ornullfor a full backup.string DisplayName-SetNamewhen the backup belongs to a set, otherwiseName.
Enums
BackupKind
Full = 0, Incremental = 1.
BackupScopeKind
WholeTree = 0, Prefix = 1, Key = 2.
BackupKeyMergeMode
LastWriterWins = 0, Crdt = 1.
LatticeRestoreMode
InPlace = 0 (a bottom-up bulk-load fast path when the target tree has never been registered and a single full whole-tree backup is restored with no narrower sub-scope, otherwise a last-writer-wins merge that converges with whatever the target already holds), ShadowCutover = 1 (build a fresh physical tree and atomically swap the registry alias).
BackupScopeRunOutcome
None = 0, Success = 1, Failure = 2, Denied = 3 (the last cycle was refused by the access gate, recorded apart from a generic Failure).
BackupHealthStatus
Unknown = 0 (never verified), Healthy = 1 (manifest and every artifact present, committed, and hash-matched), Warning = 2 (manifest present but at least one artifact missing, uncommitted, or hash-mismatched - or, for a replicated tree, the sink is not readable from a peer cluster), Missing = 3 (manifest itself absent - the catalog row is an orphan).
BackupSinkSharingEnforcement
Disabled = 0 (never probe), Warn = 1 (the default - probe, log loudly, annotate health, but start), FailFast = 2 (a positively refuted sink blocks silo start). See Configuration.
Options
LatticeBackupOptions, LatticeBackupScheduleOptions, and LatticeBackupHealthOptions are documented in full in Configuration. LatticeBackupHealthOptions configures the periodic health monitor cluster-wide: bool Enabled (default true - health monitoring is auto-enrolled) and TimeSpan DefaultInterval (default six hours), plus the static MinimumInterval (one minute) the sweep reminder clamps up to and the static DefaultSweepInterval (six hours) that DefaultInterval defaults to. The monitor stays inert against a non-durable sink regardless of these options.
Reserved-namespace guard
LatticeBackupReservedTrees
static string Prefix- the reserved tree-name prefix owned by the backup package (sys-backup-).static bool IsReserved(string treeId)-truewhentreeIdcollides with the reserved namespace. ThrowsArgumentNullExceptionwhentreeIdis null.static void ThrowIfReserved(string treeId, string? paramName = null)- throwsArgumentExceptionwhentreeIdis null, empty, or reserved.
Content addressing
BackupContentHash
static string Compute(ReadOnlySpan<byte> content)- the 64-character lowercase hexadecimal SHA-256 of the bytes.static string Compute(IEnumerable<ReadOnlyMemory<byte>> chunks)- the SHA-256 of an ordered chunk sequence, as if concatenated, without buffering the payload whole. ThrowsArgumentNullExceptionwhenchunksis null.
Metrics
BackupMetrics and LatticeBackupMetrics expose the meter, its instruments, tag/phase/reason constants, and the emission helpers. They are documented in full in Observability.
Exceptions
LatticeBackupCrossTreeFenceException : Exception
Thrown by CaptureSetAsync when a stable cross-tree fence cannot be established within the configured attempts or drain timeout. Constructors: (string message) and (string message, Exception innerException).
LatticeBackupTenantIsolationException : InvalidOperationException
Thrown by ILatticeBackupTenantScope.AuthorizeCapture / AuthorizeRestoreTarget when a capture or restore would cross the active tenant's isolation boundary. The operation is refused before any data is read or written. Constructors: (string message) and (string message, Exception innerException).
LatticeRestoreValidationException : InvalidOperationException
Thrown by RestoreAsync when a backup fails pre-apply validation (for example an artifact whose bytes do not match its recorded content digest), and by the other restore entry points - ColdRestoreAsync, RestoreSetAsync's per-member restores, RevertRestoreAsync (a named physical tree that does not belong to the target), and the ILatticeCoordinatedRestoreEngine seams. The replication package's coordinated restore path also throws it when a replicated restore is refused before it starts or aborts. Constructors: (string message) and (string message, Exception innerException).