AppSurface Search
Guide

Durable slice 2 API budget

Source of truth

View source Edit this page

Last updated

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

  • DurableCommandFingerprint and DurableCommandFingerprintMatch add versioned semantic command identity.
  • DurableWorkExecutionContext and DurablePreparedWork expose the adopter side of provider-neutral Work execution.
  • DurableProviderWorkAdapter exposes the provider side of the Work identity transition without friend access.
  • DurableWorkExitKind, DurableWorkExit<T>, DurableEncodedWorkExit, IDurableWorkExitExecutor<TWork,TResult>, and DurableWorkExitCompatibilityException add one opt-in, closed executor-fact contract. DurableWorkExitRegistration<TWork,TResult,TExecutor> and AddDurableWorkExit<TWork,TResult,TExecutor> are fixed to ProviderKeyed in 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:

  • DurableExternalActivationRequest requires the existing DurableRuntimePumpRequest plus an explicit positive cooperative RequestBudget within the .NET timer bound.
  • DurableExternalActivationOutcomeKind adds ten fixed outcomes without changing the existing four-kind DurableRuntimePumpAttemptKind algebra or its numeric values.
  • DurableExternalActivationResult validates the closed observed-state/code/pump-result combinations and retains the exact provider aggregate only for Completed.
  • IDurableExternalActivationService.ActivateAsync composes 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, and PostgreSqlDurableWorkClient. The writer preserves caller ownership of the exact Npgsql transaction; the client owns only its short convenience transaction.
  • Construction policy: PostgreSqlDurableWorkOptions and PostgreSqlDurableWakeNotificationMode make 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 : IDurableScheduleClient handles definition management, lifecycle commands, list pagination, and next-occurrence explanations.
  • PostgreSqlDurableScheduleOptions configures the required runtime role, maximum clock advance, and dispatch lease duration.
  • PostgreSqlDurableScheduleProcessRequest specifies the lease owner and maximum schedules per pass.
  • PostgreSqlDurableScheduleProcessResult reports claimed schedules, recorded occurrences, materialized Work targets, and suspended schedules.
  • PostgreSqlDurableScheduleProcessor drives 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:

  • AppSurfaceDurablePostgreSqlOptions configures process-local worker identity, bounded Pass policy, polling, liveness, shutdown reserve, and advisory wake-hint mode.
  • AppSurfaceDurablePostgreSqlServiceCollectionExtensions.AddAppSurfaceDurablePostgreSql registers 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 no IHostedService.
  • AppSurfaceDurablePostgreSqlBuilder.AddWorkerHost and AddAppSurfaceDurableWorkerHost are the deliberate opt-in for one host adapter. They retain IDurableRuntimePump as the external-activator escape hatch rather than creating a second execution API.
  • AppSurfaceDurablePostgreSqlModule declares 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.