Diagnostics and metadata
Statesman exposes diagnostics through snapshots, activity traces, metrics, manifests, and analyzer diagnostics.
Snapshot errors
loader-failed represents an acquisition attempt that produced no usable new state. Depending on policy, the fault record can retain the last-known payload.
partial-load represents a best-effort acquisition where at least one declared source succeeded or an initial fallback remained usable, but one or more sources failed. The snapshot stays Ready when it contains a newly accepted usable value, while Error makes the degradation visible.
Load metadata
Loader records reserve the statesman.* prefix. Current keys include:
statesman.load.completeness:complete,partial,initial-fallback,seeded, orretainedstatesman.load.sources.readystatesman.load.sources.faultedstatesman.initial.statusstatesman.source.<normalized-name>.status:readyorfaultedstatesman.load.duration.ms: how long the whole load took, in milliseconds, invariant culturestatesman.load.started: when the load began, round-trip (O) format, invariant culturestatesman.load.completed: when it finished, same format; alwaysstartedplus the duration
Timing is measured on the runtime's own TimeProvider, so a test driving a ManualTimeProvider reads
exact elapsed values rather than real-time bounds. These three keys are bounded: they do not grow with
the number of sources a state declares. Per-source timing is deliberately not on the record — a key
per source would scale permanent storage with the declaration, and every provider persists this
dictionary on the head record and on every history record. Read per-source timing from the
load diagnostics surface instead, or from the statesman.load.source.duration
meter instrument.
Application metadata is merged first and reserved loader metadata wins, preventing a caller from falsely reporting loader health.
Load diagnostics
IStatesman exposes structured load reports through
StatesmanDiagnosticsExtensions.TryGetDiagnostics, the same discovery call the maintenance-failure
surface uses. IStatesmanDiagnostics.ReadLoadDiagnostics() returns a LoadDiagnostics snapshot
carrying the lifetime count of completed loads, how many retained reports the bound has evicted, and
the retained reports themselves, oldest completion first. ClearLoadDiagnostics() drains them and
leaves the lifetime counts alone.
Each StateLoadReport names the address, when the load started and finished, how long it took, the
same completeness value the statesman.load.completeness metadata key carries, how many declared
sources contributed and how many threw, and one StateSourceLoadReport per source in declaration
order — its name, whether it contributed, exactly how long it took, and the type and message of what
it threw when it did not. The exception recorded is the source's own, not the wrapper the loader adds.
Retention is the latest completed load per address, bounded at
StatesmanDiagnostics.MaxRetainedLoadReports, evicting the oldest completion first. A partitioned
state's address space is unbounded, so the bound is what keeps the surface from becoming a leak.
A load that throws produces no report. RequireAll with any source failure, and a best-effort load
where no source produced state and no initial value applied, both leave the loader before an outcome
exists and become a fault snapshot instead — counted on statesman.faults and carried on the
snapshot's own StateError. A partial or initial-fallback load completes and does report, which is
where the faulted-source detail lives.
Telemetry
The core emits activities through Statesman and meters for reads, accepted commits, refreshes, faults, conflicts, operation duration, and maintenance failures (statesman.maintenance.failures, statesman.maintenance.failures.suppressed, and statesman.maintenance.failures.dropped). Tags include root, state path, partition, and operation. Avoid copying sensitive state values into tags.
See the telemetry reference for the full instrument table, the exact tag keys, and the OpenTelemetry semantic-convention audit — which two names deviate from the conventions today, and why they are kept through the 0.x line.
Pruning or cache-maintenance failure after an accepted cold append is reported as a maintenance failure and counted on statesman.maintenance.failures. It is not converted into a state fault because the authoritative state transition already succeeded. Retention of the failures themselves is rate-limited per ledger store and bounded overall — see the observability guide — and statesman.maintenance.failures.suppressed and statesman.maintenance.failures.dropped count what the rate limit and the retention bound each discarded, respectively.
Analyzer diagnostics
STM001: a member of a[ManagedState]type is directly assigned outside an explicit boundarySTM002: a[ManagedState]type exposes a public mutable field or setterSTM003:StateKey.Define<T>receives a non-constant path and can destabilize the manifestSTM004: a collection reached through a[ManagedState]type is mutated in place outside an explicit boundary
Use [StateMutationBoundary] for a documented reducer, importer, mapper, or legacy adapter. Use [StateMutationAnalysisIgnore] only at a narrow symbol with a concrete reason. STM002 ships code fixes (init-only property, readonly field) with fix-all support; the other three are documentation only. Each diagnostic carries a HelpLinkUri to its section of the analyzer guide.