ForgeTrust.AppSurface.Durable.Provider
0.2.0-preview.6
dotnet add package ForgeTrust.AppSurface.Durable.Provider --version 0.2.0-preview.6
NuGet\Install-Package ForgeTrust.AppSurface.Durable.Provider -Version 0.2.0-preview.6
<PackageReference Include="ForgeTrust.AppSurface.Durable.Provider" Version="0.2.0-preview.6" />
<PackageVersion Include="ForgeTrust.AppSurface.Durable.Provider" Version="0.2.0-preview.6" />
<PackageReference Include="ForgeTrust.AppSurface.Durable.Provider" />
paket add ForgeTrust.AppSurface.Durable.Provider --version 0.2.0-preview.6
#r "nuget: ForgeTrust.AppSurface.Durable.Provider, 0.2.0-preview.6"
#:package ForgeTrust.AppSurface.Durable.Provider@0.2.0-preview.6
#addin nuget:?package=ForgeTrust.AppSurface.Durable.Provider&version=0.2.0-preview.6&prerelease
#tool nuget:?package=ForgeTrust.AppSurface.Durable.Provider&version=0.2.0-preview.6&prerelease
ForgeTrust.AppSurface.Durable.Provider
Public preview: the
PostgreSQL providersupplies the current conformance path. This package contains SPI contracts, not a runtime.
ForgeTrust.AppSurface.Durable.Provider is the runtime-provider and operator SPI for
ForgeTrust.AppSurface.Durable. It depends on that adopter package; the
adopter package never depends on Provider. Production providers implement this public SPI without friend access.
Choose this package when
- implementing a storage/runtime provider;
- hosting a bounded provider pump explicitly;
- exposing application-authorized health, drain, recovery, or operator operations; or
- adapting a provider claim to an adopter-registered Work executor.
Ordinary applications and reusable modules should reference only ForgeTrust.AppSurface.Durable. This package does not
provide PostgreSQL storage, migrations, polling, schedule execution, hosted services, endpoints, metrics, or tracing.
Slice 7 discovery boundary
This SPI remains a public preview. Provider contracts describe activation and operator boundaries, but storage
registration is passive and does not imply
worker hosting. The PostgreSQL provider requires an explicit
AddWorkerHost() opt-in for continuous
processing.
An opted-in host validates schema compatibility and the active runtime epoch during startup, then fails closed when they are incompatible. Startup never applies DDL or rewrites migration history. The ordered schema and reconciliation flow is documented in the Slice 7 Durable guide.
Activation and broker evolution
IDurableRuntimePump is the common bounded activation primitive for a continuously hosted loop, scheduled job,
function, HTTP wake-up, or broker notification. A wake-up is advisory: implementations must recover eligible work from
their authoritative state even when notifications are lost, duplicated, delayed, or reordered.
Do not translate broker receipt into a claim, effect permit, or terminal fact. A wake-only adapter must call the pump without carrying application payloads. A future targeted-dispatch or broker-native provider must revalidate its opaque reference against authoritative scope, revision, lease, runtime-epoch, and provider-effect state before invoking work. Slice 2 leaves that adapter shape open until a concrete broker topology proves the required routing and acknowledgement contract.
Public API by audience
Every public type in this package belongs to one of these provider-facing families. The member-level API snapshot is the canonical inventory.
| Audience | Public types | Contract role |
|---|---|---|
| Runtime implementers | DurableRuntimeSurface, DurableRuntimePumpRequest, DurableRuntimePumpResult, IDurableRuntimePump |
Run one bounded, externally activated pass |
| Health and host implementers | DurableRuntimeHealthState, DurableRuntimeHealthSnapshot, IDurableRuntimeHealth, IDurableRuntimeDrainControl |
Report low-cardinality health and coordinate graceful drain |
| Work-store implementers | DurableClaimedWork, DurablePreparedWorkInvocation, DurableProviderWorkAdapter |
Validate a claim, derive immutable execution identity, and invoke the adopter registry |
| Application-authorized control implementers | Work get/cancel/list/snapshot types and IDurableWorkControlClient; scope disable types and IDurableScopeControlClient |
Expose bounded, scoped, payload-free operational control |
| Application-authorized operator implementers | Operator outcome/resolution/result/request types and IDurableWorkOperatorClient |
Reconcile, resolve, safely retry, or recovery-release suspended Work |
| Application-authorized retention implementers | IDurableFlowRetentionClient, bounded assessment/manifest/package/receipt/hold/purge types |
Prove one exact terminal Flow source set before a separately authorized purge |
| Flow-repair operator implementers | IFlowRepairOperatorClient, repair request/evidence/assessment/result/receipt types |
Inspect and repair only the two evidence-backed child-effect assertions |
The SPI accepts and returns public Durable identifiers and command fingerprints. Collection results defensively copy inputs, default identifiers are rejected, timestamps normalize to UTC, page sizes are bounded, and every mutation uses revision/generation fencing. Provider worker ids, terminal/problem codes, and registered Work names and versions use the Durable package's canonical identifier alphabet and bounds.
Provider work adaptation
A provider constructs DurableClaimedWork only after it owns a validated claim. Prepare maps that claim to the
adopter-facing DurableWorkExecutionContext and resolves the registered executor. The resulting
DurablePreparedWorkInvocation owns encoded input and exposes only the public invocation boundary.
The execution identity transition is enforceable: create the first identity from an activity id and current fences,
then call Advance for a later attempt/lease/scope/runtime epoch. The provider key remains exactly the activity id so
lease turnover cannot create a new external idempotency identity.
Command fingerprints
Work reconcile, manual resolution, safe retry, and recovery release each use a distinct v1 fingerprint schema. A
provider persists the schema id and digest with command outcome truth. A repeated command id with UnsupportedSchema or
Conflict fails closed; it must never repeat reconciliation merely because the command id matches.
Flow repair operator preview
IFlowRepairOperatorClient is a separate application-authorized boundary for an
ASDUR211 child-effect suspension. It intentionally exposes
only AssertChildEffectCompleted and AssertChildEffectNotApplied. The first binds a retained terminal Work result;
the second binds a named completed manual-resolution command whose persisted resolution_kind is
proven_not_applied. Neither action can release an arbitrary suspension, mutate the child Work, invoke an executor,
or force terminate an ambiguous effect.
Call GetAssessmentAsync with a trusted scope and Flow id to obtain an advisory, payload-free candidate. The
assessment can go stale; submit the selected action through a fresh revision- and descriptor-digest-fenced request.
RepairAsync returns an immutable receipt only for Applied and Duplicate; Refused, RaceLost, and Conflict
carry no receipt. The receipt digest binds the request schema/digest, descriptor, action-specific Work history fact,
audit actor/reason, transition states, and accepted timestamp. It is integrity evidence, not a signature or a claim
that ActorId authorized the caller.
Do not call IDurableFlowClient.ReleaseSuspensionAsync as a fallback for this descriptor. The PostgreSQL provider
rejects that broad lifecycle command with ASDUR211; follow the normative
Flow repair protocol instead.
Verified Flow retention
IDurableFlowRetentionClient is an evidence boundary, not a cleanup scheduler. An application first assesses exactly
one Flow and receives Safe, Blocked, or Indeterminate with a typed reason. Only a still-matching safe assessment
can create an immutable manifest. The provider then builds a reproducible DFA1 package, records an adopter-supplied
archive receipt, verifies source correspondence, permits an application-owned hold, and accepts a separate
compare-and-swap purge command.
Canonical retention API reference
| Operation | Request type | Result payload | Required state | Next sequence |
|---|---|---|---|---|
AssessAsync |
DurableRetentionAssessmentRequest |
DurableRetentionAssessment |
Terminal Flow | N/A |
CreateManifestAsync |
DurableRetentionManifestCreateRequest |
DurableRetentionManifestCreateResult |
Safe assessment |
1 (Frozen) |
BuildArchivePackageAsync |
(scopeId, manifestId) |
DurableArchivePackageV1 |
Any active manifest | Unchanged |
RecordArchiveReceiptAsync |
DurableRetentionRecordArchiveReceiptRequest |
DurableRetentionMutationResult |
Frozen, sequence 1 |
2 (ArchiveReceiptRecorded) |
VerifyArchiveAsync |
DurableRetentionVerifyArchiveRequest |
DurableRetentionMutationResult |
ArchiveReceiptRecorded, sequence 2 |
3 (Verified) |
SetHoldAsync |
DurableRetentionHoldRequest |
DurableRetentionMutationResult |
Verified or Held |
Next monotonic sequence |
PurgeAsync |
DurableRetentionPurgeRequest |
DurableRetentionMutationResult |
Verified, no active hold |
Next monotonic sequence (Purged) |
Lifecycle state sequence and boundaries
The retention lifecycle uses monotonic sequence checks to prevent out-of-order or duplicate execution:
- Assessment & Manifest:
AssessAsyncevaluates one Flow against boundary limits (maximum 10,000 closure items and 64 MiB package bytes). Non-safe outcomes (Blockeddue to active child Work, nonterminal state, or repair required;Indeterminatedue to unknown state) forbid manifest creation.CreateManifestAsyncfreezes source hashes and initializesLifecycleSequence = 1inFrozenstate. - Archive & Receipt:
BuildArchivePackageAsyncconstructs the canonicalDFA1archive byte array. The adopter writes the archive package to external storage and callsRecordArchiveReceiptAsyncwith sequence 1. - Verification:
VerifyArchiveAsyncvalidates source SHA-256 correspondence against the frozen manifest, advances state toVerified, and incrementsLifecycleSequenceto 3. - Hold & Purge:
SetHoldAsynccan place or release a legal hold (PlaceHold = true/false) and increments the sequence for every applied transition.PurgeAsyncrequires stateVerified, no active hold, and the current sequence. It transitions state toPurged, clears terminal payloads, and deletes manifest-covered history rows.
Common failures and pitfalls
ASDUR102(Command Conflict): Reusing a command identity with different request parameters fails closed.ASDUR214(Manifest Not Found): Specified manifest ID does not exist in the authorized scope.ASDUR215(Source Changed): Live Flow source items changed after assessment or manifest creation. Caller must create a new assessment and manifest.ASDUR216(Sequence Conflict): Expected lifecycle sequence is stale. Reload manifest state before retrying.ASDUR217(Lifecycle Rejected): Operation attempted out of order (e.g. purging before verification or while a legal hold is active).
The application must authorize every call and owns archive transport, encryption, retention duration, availability, and legal/compliance requirements. Receipt verification proves the package corresponds to the frozen PostgreSQL source; it does not prove external bytes are present or adequate. No API accepts an archive URI, raw SQL, age-range deletion, continuation token, or multi-Flow manifest. See the PostgreSQL retention deployment guidance.
Operational prerequisites
Before a provider is included in a coordinated prerelease, release review must verify storage and migration ownership, polling/schedule execution, restore fencing, graceful drain, privacy-bounded diagnostics and telemetry, packed-consumer proof, verified-retention evidence when the retention SPI is implemented, and conformance tests against this SPI. The PostgreSQL provider supplies Work, Flow, Schedule, hosted activation, drain/recovery, retention, and repair conformance; the review checklist remains the prerelease publication gate.
See the ASDURxxx diagnostics catalog for currently available contract,
PostgreSQL Work, and hosted-runtime codes.
From the repository root, ./Durable/verify-packed-consumers.sh packs the three public-preview packages and their local
dependencies, then compiles and runs isolated adopter and provider consumers against only those packages.
Release Guidance
AppSurface ships as a coordinated package family. Before installing this package from a prerelease feed, check the package chooser and release hub for current release risk, migration guidance, and readiness.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- CliWrap (>= 3.10.1)
- ForgeTrust.AppSurface.Durable (>= 0.2.0-preview.6)
- Microsoft.Extensions.DependencyInjection (>= 10.0.8)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Hosting (>= 10.0.8)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Logging.Console (>= 10.0.8)
- Microsoft.Extensions.Options (>= 10.0.8)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ForgeTrust.AppSurface.Durable.Provider:
| Package | Downloads |
|---|---|
|
ForgeTrust.AppSurface.Durable.PostgreSql
ForgeTrust.AppSurface.Durable.PostgreSql package for AppSurface application composition. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.2.0-preview.6 | 123 | 8/12/2026 |