.NET API
IStatePreflightReader
Tracon.Abstractions.dllReads the stored state generations WITHOUT writing anything, so an operator can ask “can this build still read my data” BEFORE upgrading.
public interface IStatePreflightReaderRemarks
Section titled “Remarks”This surface is deliberately separate from ISessionStore and IWorkflowCheckpointStore. Those two are application surfaces scoped to one tenant: they filter every read by the tenant in scope, page their results, and pull the full state payload of every row. A preflight asks a different question — how many rows exist per generation, across every tenant at once — and answering it by paging through the application surface would drag the entire state column across the wire.
Tenant mode — tenant-independent. Nothing here takes or applies a tenant identifier, and that is the point rather than an omission: an upgrade replaces the process for every tenant at the same moment, so a count that saw only one tenant would under-report the very risk this surface exists to measure. Never expose its results through a per-tenant API: a row count is information about other tenants.
Delivery — no delivery guarantee applies. Every method is a synchronous read that returns its own result; nothing is queued, retried, or handed to another party. A failed call throws and has changed nothing, so the caller’s only recovery is to call again.
Nothing here writes. Every implementation runs read-only queries and takes no lock; it is safe to run against a live database while the application is serving traffic.
The values returned are raw: this reader reports what is stored, never
whether the running build understands it. That comparison belongs to
StatePreflight in Tracon.Core, the only layer that knows
which generation the current code writes.
DI lifetime — singleton. Registered with Replace by
whichever SQL provider is active. No implementation is registered when
persistence is in memory; resolve it as optional.
Properties
Section titled “Properties”ProviderName
Section titled “ ProviderName”Gets the provider name, for example PostgreSQL.
string ProviderName { get; }Property Value
Section titled “Property Value”Methods
Section titled “Methods”SampleAsync(StatePreflightTarget, int, CancellationToken)
Section titled “ SampleAsync(StatePreflightTarget, int, CancellationToken)”Reads at most perGeneration rows of each generation, newest first.
ValueTask<IReadOnlyList<StateSample>> SampleAsync(StatePreflightTarget target, int perGeneration, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”target StatePreflightTarget
The table to sample.
perGeneration int
The maximum number of rows to read per generation. 0 reads nothing.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<StateSample>>
The sampled rows, state payload included.
Remarks
Section titled “Remarks”The sample is taken PER GENERATION rather than “the newest N rows overall”: the newest rows are the ones the running build just wrote, so they prove nothing. The risk concentrates in the older generations.
TallyAsync(StatePreflightTarget, CancellationToken)
Section titled “ TallyAsync(StatePreflightTarget, CancellationToken)”Counts the rows of target per stored schema generation.
ValueTask<IReadOnlyList<StateGenerationTally>> TallyAsync(StatePreflightTarget target, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”target StatePreflightTarget
The table to count.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<IReadOnlyList<StateGenerationTally>>
One entry per distinct generation. An empty table returns an empty list, never an error.
Remarks
Section titled “Remarks”A single aggregate query over the whole table; the state payload is never read. Rows of every tenant are counted, because an upgrade is not a per-tenant event.