IStageTermination
NexusLabs.Needlr.AgentFramework¶
NexusLabs.Needlr.AgentFramework.Diagnostics¶
IStageTermination Interface¶
Contract for any value that describes why a pipeline stage terminated. Implemented by the framework's closed StageTermination hierarchy (12 framework cases including the Custom escape hatch) and — optionally — by consumer-defined types when a typed extension case is required.
Derived
↳ StageTermination
Remarks¶
Framework cases — the easy path. Most consumers should use the framework's
StageTermination hierarchy directly. The 11 typed framework cases
cover every loop-natural, loop-bounded, external, and stage-level termination the
runner produces; the Custom case carries
app-specific narrative with a Reason string and an optional structured
Properties dictionary. Framework cases are JSON-polymorphism-registered
on this interface, so they round-trip through System.Text.Json.JsonSerializer
out of the box.
Custom cases — the typed extension path. Consumers who need a typed
extension case (with named-record pattern matching like
is MyDomainTermination { FindingCount: var c }) can implement this
interface directly:
public sealed record MyDomainTermination(int FindingCount) : IStageTermination
{
public string ToTagValue() => "MyDomain";
}
Implementing this interface is a contract: you own the JSON serialization for your derived type. The framework's System.Text.Json.Serialization.JsonPolymorphicAttribute registry on this interface only knows about the framework cases — your type is not in it. Two practical options: 1. Register your derived type at the JSON layer via a System.Text.Json.Serialization.Metadata.JsonTypeInfoResolver modifier so it joins the polymorphism table for that System.Text.Json.JsonSerializerOptions instance. 2. Provide your own System.Text.Json.Serialization.JsonConverter<> for IStageTermination with full control over the wire format.
If you do neither, JsonSerializer.Serialize<IStageTermination>(yourInstance)
throws System.NotSupportedException — same loud failure the
framework cases have today for unregistered types. There is no silent
data loss, but every JSON-serialising downstream consumer needs the
registration. If you don't want to maintain a JSON registration, use
StageTermination itself is closed for external derivation at compile time (its constructor is internal) — the framework hierarchy is exhaustive by design. Extension happens by implementing this interface directly, not by inheriting from the abstract record.
Methods¶
IStageTermination.ToTagValue() Method¶
Returns a stable, low-cardinality string suitable for OpenTelemetry tag values
(e.g. the termination_cause tag emitted by
IPipelineMetrics). Framework cases return their case name
(e.g. "MaxIterationsReached", "Custom") — bounded by the case
enumeration. Free-form detail such as Reason
is preserved on the record / in JSON rather than in this tag, so the metric stays
bounded by default. Third-party implementations are responsible for their own
cardinality discipline — the returned string is used directly as a metric tag value.