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

All three packages 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.

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.