Durable slice 2 API budget
Source of truth
This ledger records how the public surface from the original durable-contract commit was treated when the contract was rebuilt as three preview packages. The checked-in Durable, Provider, and PostgreSQL snapshots are the exhaustive member-level source of truth; this ledger explains the intentional package and visibility decisions.
Retained adopter API
Every public type in the ForgeTrust.AppSurface.Durable snapshot remains public in that package unless it appears in
the additions below. These are the adopter-facing Work, Flow, Schedule, serialization, registration, and client
contracts. No adopter-facing public type was removed or internalized.
Moved provider API
Every public type in the ForgeTrust.AppSurface.Durable.Provider snapshot other than DurableProviderWorkAdapter was
retained from the original contract and moved from the adopter assembly into the Provider package. This includes the
runtime pump, runtime health, drain, claimed-work, control, recovery, and operator families. The move establishes the
one-way package dependency Provider to Durable and replaces the original internal/friend provider seam.
Added public API
DurableCommandFingerprintandDurableCommandFingerprintMatchadd versioned semantic command identity.DurableWorkExecutionContextandDurablePreparedWorkexpose the adopter side of provider-neutral Work execution.DurableProviderWorkAdapterexposes the provider side of the Work identity transition without friend access.DurableWorkExitKind,DurableWorkExit<T>,DurableEncodedWorkExit,IDurableWorkExitExecutor<TWork,TResult>, andDurableWorkExitCompatibilityExceptionadd one opt-in, closed executor-fact contract.DurableWorkExitRegistration<TWork,TResult,TExecutor>andAddDurableWorkExit<TWork,TResult,TExecutor>are fixed toProviderKeyedin V1, while the legacy worker executor and registration APIs remain additive and unchanged.
Internalized or removed implementation seams
Canonicalization, identifier validation, provider validation, and fingerprint construction remain internal helpers; they are implementation details behind validated public constructors. The original internal schedule/provider friend seam was removed. No public type was deleted outright.
Compatibility rule
The Durable, Provider, and PostgreSQL packages covered by this ledger are public previews in the coordinated prerelease publish plan. The PostgreSQL provider supplies Work, Flow, Schedule, hosted runtime, drain/recovery, retention, repair, and restore-fencing conformance. Every public member change must update the appropriate deterministic API snapshot and this ledger when it changes a type's audience, package, or visibility. The first supported publication and any persisted deployment are independent compatibility boundaries: whichever happens first freezes canonical bytes, and every later canonical-byte change requires a new schema id.
External activation v1 (#804)
The Provider package adds four public activation contracts and one passive registration extension:
DurableExternalActivationRequestrequires the existingDurableRuntimePumpRequestplus an explicit positive cooperativeRequestBudgetwithin the .NET timer bound.DurableExternalActivationOutcomeKindadds ten fixed outcomes without changing the existing four-kindDurableRuntimePumpAttemptKindalgebra or its numeric values.DurableExternalActivationResultvalidates the closed observed-state/code/pump-result combinations and retains the exact provider aggregate only forCompleted.IDurableExternalActivationService.ActivateAsynccomposes current health observation with exactly one authoritative admission call and a separate caller token.DurableExternalActivationServiceCollectionExtensions.AddDurableExternalActivation()repeat-safely registers the singleton service,TimeProvider.System, and logging without creating a host, route, timer, connection, schema change, or exporter.
The namespace is ForgeTrust.AppSurface.Durable.Provider. The concrete service and per-invocation phase/clock/resource
helper remain internal. Existing direct IDurableRuntimePumpAdmission and legacy IDurableRuntimePump callers retain
their contracts and are not redirected. The
versioned activation reference documents the decision to add this orchestration surface,
its constraints, host ownership, failure mapping, and telemetry. The Provider
PublicAPI.Shipped.txt snapshot remains the exhaustive
member inventory.
Slice 3 PostgreSQL API
The public-preview ForgeTrust.AppSurface.Durable.PostgreSql package adds thirteen public types in three deliberate
families. Its checked-in PublicAPI.Shipped.txt is the exhaustive member inventory.
- Schema deployment:
IDurableRuntimeSchemaManager,PostgreSqlDurableRuntimeSchemaManager, schema status, compatibility, apply/activation/rotation results, and the schema exception. These operations require a migration-owner data source and never run automatically at runtime startup. - Work acceptance:
IDurableWorkTransactionWriter,PostgreSqlDurableWorkTransactionWriter, andPostgreSqlDurableWorkClient. The writer preserves caller ownership of the exact Npgsql transaction; the client owns only its short convenience transaction. - Construction policy:
PostgreSqlDurableWorkOptionsandPostgreSqlDurableWakeNotificationModemake StoreId, runtime epoch, and default-disabled wake hints explicit without exposing internal claim/store operations.
Discovery, recovery, claim, renew, preparation failure, permit, completion, cancellation, scope disablement, operator reconciliation, manual resolution, safe retry, recovery release, and stale-observation types remain internal. Slice 6 must prove the smallest hosting and operator SPI before any of those types become public.
Slice 4 PostgreSQL Flow API
Slice 4 adds exactly one public PostgreSQL runtime type:
PostgreSqlDurableFlowClient : IDurableFlowClient. Its constructor requires the scoped NpgsqlDataSource, exact
IDurableFlowRegistry, explicit IDurablePayloadCodecRegistry, and the existing
PostgreSqlDurableWorkOptions. Reusing the options type avoids a duplicate public configuration surface for StoreId,
runtime epoch, and wake-hint behavior.
The Flow processor, dispatch candidates/results, lease settings, barrier observer, command store, decision writer, timer resolver, child-Work acceptance seam, and Work-to-Flow projector remain internal. Hosted activation, health, drain, and public operator SPI decisions remain slice 6.
The existing Flow list continuation-token shape is unchanged. Its validated preview bound increases from 200 to 512 characters so the versioned base64url keyset token can carry an exact UTC update key and instance identity without truncation. Tokens remain opaque, payload-free, scope-local query inputs and reject unknown versions or malformed encodings.
Slice 5 PostgreSQL Schedule API
Slice 5 adds five public PostgreSQL schedule types:
PostgreSqlDurableScheduleClient : IDurableScheduleClienthandles definition management, lifecycle commands, list pagination, and next-occurrence explanations.PostgreSqlDurableScheduleOptionsconfigures the required runtime role, maximum clock advance, and dispatch lease duration.PostgreSqlDurableScheduleProcessRequestspecifies the lease owner and maximum schedules per pass.PostgreSqlDurableScheduleProcessResultreports claimed schedules, recorded occurrences, materialized Work targets, and suspended schedules.PostgreSqlDurableScheduleProcessordrives manual, bounded evaluation passes using separate dispatcher and runtime data sources.
Slice 6 PostgreSQL runtime operations API
Slice 6 adds the explicit PostgreSQL composition surface rather than widening the portable Provider contracts:
AppSurfaceDurablePostgreSqlOptionsconfigures process-local worker identity, bounded Pass policy, polling, liveness, shutdown reserve, and advisory wake-hint mode.AppSurfaceDurablePostgreSqlServiceCollectionExtensions.AddAppSurfaceDurablePostgreSqlregisters passive storage, clients, schema manager, pump, health, and drain from explicit dispatcher/runtime data sources and existing Work and Schedule options. It opens no connection, applies no migration, and installs noIHostedService.AppSurfaceDurablePostgreSqlBuilder.AddWorkerHostandAddAppSurfaceDurableWorkerHostare the deliberate opt-in for one host adapter. They retainIDurableRuntimePumpas the external-activator escape hatch rather than creating a second execution API.AppSurfaceDurablePostgreSqlModuledeclares only the passive Durable module dependency. It never guesses credentials or activates a worker.
The runtime pump, health, and drain interfaces remain owned by ForgeTrust.AppSurface.Durable.Provider. PostgreSQL
claim stores, heartbeat generation operations, listener state, execution wrapper, and hosted service stay internal so
Issue #685 can instrument the execution wrapper without duplicating trace context or broadening the public API.
Typed Work-exit provider boundary
DurablePreparedWork.InvokeExitAsync and DurablePreparedWorkInvocation.InvokeExitAsync are additive compatibility
bridges, not a general completion-model replacement. The default bridge wraps legacy success; an exit-aware Work's
legacy invocation accepts success only and otherwise raises the public, payload-free
DurableWorkExitCompatibilityException. PostgreSQL keeps its encoded-exit execution boundary and completion
translator internal, preserving the existing store, SQL, migrations, and provider-owned retry policy.
Typed Work definitions (#800)
The typed Work migration guide introduces five public types in the existing
adopter package: DurableWork, DurableWorkDefinition<TWork,TResult>,
DurableWorkBinding<TWork,TResult,TExecutor>,
DurableReconciledWorkBinding<TWork,TResult,TExecutor,TReconciler>, and
DurableExitWorkBinding<TWork,TResult,TExecutor>. The static factory requires an explicit retry default; sealed,
get-only definitions and bindings have internal constructors. Three AddDurableWork overloads infer implementation
types from the binding. The request factory retains explicit caller identities, retry overrides and eligibility time.
The shared contract/codec snapshots, provenance checks, contribution aggregator and local registration catalog are internal. Existing registration constructors and request APIs remain supported; Work and Flow fingerprints and the provider execution boundary are unchanged. Flow uses compatible codecs from the same original source without relaxing its exact Work-registration reference requirement. The API snapshot records every member and generic constraint.
Deterministic execution-policy v1 (#765)
The existing retry-policy and Work-request constructors, typed Define, CreateRequest, DurableClaimedWork, and
DurableWorkSnapshot constructor signatures remain. The Durable package adds the closed immutable
DurableAttemptPlan, DurableExecutionDeadline, DurableWorkExecutionPolicy, and DurableWorkExecutionSnapshot
contracts; DurableWork.DefineWithExecutionPolicy, DurableWorkRequest.CreateWithExecutionPolicy, and
DurableWorkDefinition<TWork,TResult>.CreateRequestWithExecutionPolicy; and read-only execution-policy/deadline
projections. The Provider package adds named execution-aware claim and inspection factories while keeping old
constructors and nullable legacy Execution projections. Core and Provider API snapshots remain the exhaustive member
inventory.
The Testing checkpoint controller
adds a cursor overload of WaitForObservationAsync(name, afterSequence, maximumWait, cancellationToken) for later
attempt observations while preserving the original name-and-cancellation signature. Its Testing API snapshot
is the exhaustive helper inventory; checkpoint observations remain descriptive test facts.
No PostgreSQL public type or Workers-envelope metadata is added for this feature. Storage schema 12 adds nullable
execution fields without backfilling legacy rows. Existing requests keep v1 fingerprint bytes; opt-in requests use v2.
The canonical chooser/reference and migration checklist
cover defaults, validation, deadline semantics, safe effect truth, and rollout/rollback constraints.