Documentation
¶
Overview ¶
Package resolver provides type coercion utilities.
Type coercion functions have been moved to pkg/spec/types.go. This file is kept for backward compatibility - CoerceType is re-exported in resolver.go from the spec package.
Package resolver provides types for defining and executing data resolvers.
This file re-exports types from pkg/spec for backward compatibility. New code should import from pkg/spec directly when possible.
Index ¶
- Constants
- Variables
- func ExtractDependencies(r *Resolver, lookup DescriptorLookup) []string
- func ExtractInferredDependencies(r *Resolver, lookup DescriptorLookup) []string
- func ExtractOptionalRefsFromValueRef(ref *ValueRef, optional map[string]bool)
- func ExtractRefsFromValueRef(ref *ValueRef, deps map[string]bool)
- func ExtractRefsFromValueRefs(inputs map[string]*ValueRef) []string
- func FormatDiffHuman(diff *SnapshotDiff) string
- func FormatDiffJSON(diff *SnapshotDiff) (string, error)
- func FormatDiffUnified(diff *SnapshotDiff) string
- func FormatMetricsSummary(summary *MetricsSummary) string
- func GetMaxPhase(phases []*PhaseGroup) int
- func GetPhaseForResolver(phases []*PhaseGroup, resolverName string) int
- func IsAggregatedExecutionError(err error) bool
- func IsCircularDependencyError(err error) bool
- func IsExecutionError(err error) bool
- func IsForEachTypeError(err error) bool
- func IsTransitiveDependency(resolvers map[string]*Resolver, targetResolver, candidateName string) bool
- func IsTypeCoercionError(err error) bool
- func IsValidationError(err error) bool
- func IsValueSizeError(err error) bool
- func RecordResolverExecution(resolverName string, result *ExecutionResult)
- func RedactError(err error, sensitive bool) error
- func RedactMapValues(m map[string]any, sensitive bool) map[string]any
- func RedactSensitiveValues(snapshot *Snapshot, resolvers []ResolverLike)
- func RedactValue(value any, sensitive bool) any
- func RegisterResolverMetrics()
- func SaveSnapshot(snapshot *Snapshot, filePath string) error
- func WithContext(ctx context.Context, rc *Context) context.Context
- type AggregatedDeferredValidationError
- type AggregatedExecutionError
- func (e *AggregatedExecutionError) Add(resolverName string, phase int, err error)
- func (e *AggregatedExecutionError) AddSkipped(resolverName string)
- func (e *AggregatedExecutionError) Error() string
- func (e *AggregatedExecutionError) HasErrors() bool
- func (e *AggregatedExecutionError) IncrementSucceeded()
- type AggregatedValidationError
- type AttemptDetail
- type BuildResult
- type CircularDependencyError
- type Condition
- type Config
- type ConfigInput
- type Context
- func (c *Context) DeferredValidation() *DeferredValidationSummary
- func (c *Context) Get(name string) (any, bool)
- func (c *Context) GetAllResults() map[string]*ExecutionResult
- func (c *Context) GetResult(name string) (*ExecutionResult, bool)
- func (c *Context) Has(name string) bool
- func (c *Context) Set(name string, value any)
- func (c *Context) SetDeferredValidation(summary *DeferredValidationSummary)
- func (c *Context) SetResult(name string, result *ExecutionResult)
- func (c *Context) ToMap() map[string]any
- type DeferredReportingPlan
- type DeferredValidationFailure
- type DeferredValidationSummary
- type DeferredValidationUnit
- type DescriptorLookup
- type DiffOptions
- type DiffSummary
- type DiffType
- type ErrorBehavior
- type ExecutionError
- type ExecutionResult
- type ExecutionStatus
- type Executor
- type ExecutorOption
- func OptionsFromAppConfig(cfg ConfigInput) []ExecutorOption
- func WithCalls(calls map[string]*spec.Call) ExecutorOption
- func WithDefaultTimeout(timeout time.Duration) ExecutorOption
- func WithDeferredValidation(enabled bool) ExecutorOption
- func WithMaxConcurrency(maxConcurrency int) ExecutorOption
- func WithMaxValueSize(bytes int64) ExecutorOption
- func WithMockedResolvers(mocks map[string]any) ExecutorOption
- func WithNonFatalValidation(enabled bool) ExecutorOption
- func WithPhaseTimeout(timeout time.Duration) ExecutorOption
- func WithProgressCallback(callback ProgressCallback) ExecutorOption
- func WithSkipTransform(enabled bool) ExecutorOption
- func WithSkipValidation(enabled bool) ExecutorOption
- func WithValidateAll(enabled bool) ExecutorOption
- func WithWarnValueSize(bytes int64) ExecutorOption
- type FailedAttemptSummary
- type FailedResolver
- type FailureSummary
- type FieldChange
- type ForEachClause
- type ForEachIterationResult
- type ForEachTypeError
- type Graph
- type GraphDependency
- type GraphDiagrams
- type GraphEdge
- type GraphNode
- type GraphStats
- type IterationContext
- type Messages
- type MetricsSummary
- type PhaseGroup
- type PhaseInfo
- type PhaseMetrics
- type PhaseTimeoutError
- type Plan
- type PlanData
- type ProgressCallback
- type ProviderAttempt
- type ProviderSource
- type ProviderTransform
- type ProviderValidation
- type RedactedError
- type RegistryInterface
- type ResolvePhase
- type Resolver
- type ResolverDiff
- type ResolverLike
- type ResolverMetric
- type Snapshot
- type SnapshotDiff
- type SnapshotFailedAttempt
- type SnapshotMetadata
- type SnapshotPhase
- type SnapshotResolver
- type SnapshotRuntime
- type SnapshotRuntimeComponent
- type TemplateAccessor
- type TransformPhase
- type Type
- type TypeCoercionError
- type ValidatePartition
- type ValidatePhase
- type ValidationFailure
- type ValueRef
- type ValueSizeError
Constants ¶
const ( TypeString = spec.TypeString TypeInt = spec.TypeInt TypeFloat = spec.TypeFloat TypeBool = spec.TypeBool TypeArray = spec.TypeArray TypeTime = spec.TypeTime TypeDuration = spec.TypeDuration TypeAny = spec.TypeAny )
Type constants re-exported from spec for backward compatibility.
const ( ErrorBehaviorFail = spec.OnErrorFail ErrorBehaviorContinue = spec.OnErrorContinue )
ErrorBehavior constants re-exported from spec for backward compatibility.
Variables ¶
var ( // ResolverExecutionDuration tracks the duration of resolver executions ResolverExecutionDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: fmt.Sprintf("%s_resolver_execution_duration_seconds", settings.CliBinaryName), Help: "Histogram of resolver execution duration in seconds", Buckets: []float64{.01, .05, .1, .25, .5, 1, 2.5, 5, 10, 30}, }, []string{resolverNameLabel, statusLabel}) // ResolverPhaseDuration tracks the duration of individual resolver phases ResolverPhaseDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: fmt.Sprintf("%s_resolver_phase_duration_seconds", settings.CliBinaryName), Help: "Histogram of resolver phase duration in seconds", Buckets: []float64{.01, .05, .1, .25, .5, 1, 2.5, 5, 10, 30}, }, []string{resolverNameLabel, phaseLabel}) // ResolverExecutionsTotal tracks the total number of resolver executions ResolverExecutionsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: fmt.Sprintf("%s_resolver_executions_total", settings.CliBinaryName), Help: "Total number of resolver executions", }, []string{resolverNameLabel, statusLabel}) // ResolverProviderCallsTotal tracks the total number of provider calls made by resolvers ResolverProviderCallsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: fmt.Sprintf("%s_resolver_provider_calls_total", settings.CliBinaryName), Help: "Total number of provider calls made by resolvers", }, []string{resolverNameLabel, providerLabel, phaseLabel}) // ResolverValueSize tracks the size of resolver values in bytes ResolverValueSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: fmt.Sprintf("%s_resolver_value_size_bytes", settings.CliBinaryName), Help: "Histogram of resolver value sizes in bytes", Buckets: []float64{100, 1000, 10000, 100000, 1000000, 10000000}, }, []string{resolverNameLabel}) // ResolverDependencyCount tracks the number of dependencies per resolver ResolverDependencyCount = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: fmt.Sprintf("%s_resolver_dependency_count", settings.CliBinaryName), Help: "Histogram of resolver dependency counts", Buckets: []float64{0, 1, 2, 5, 10, 20, 50}, }, []string{resolverNameLabel}) // ResolverFailedAttemptsTotal tracks the total number of failed provider attempts ResolverFailedAttemptsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: fmt.Sprintf("%s_resolver_failed_attempts_total", settings.CliBinaryName), Help: "Total number of failed provider attempts before success or final failure", }, []string{resolverNameLabel, providerLabel, phaseLabel}) // ResolverPhaseExecutionsTotal tracks the total number of phase executions ResolverPhaseExecutionsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: fmt.Sprintf("%s_resolver_phase_executions_total", settings.CliBinaryName), Help: "Total number of resolver phase executions", }, []string{phaseLabel}) // ResolverConcurrentExecutions tracks the current number of concurrent resolver executions ResolverConcurrentExecutions = prometheus.NewGauge(prometheus.GaugeOpts{ Name: fmt.Sprintf("%s_resolver_concurrent_executions", settings.CliBinaryName), Help: "Current number of concurrent resolver executions", }) )
var CoerceType = spec.CoerceType
CoerceType is re-exported from spec for backward compatibility.
Functions ¶
func ExtractDependencies ¶ added in v0.2.0
func ExtractDependencies(r *Resolver, lookup DescriptorLookup) []string
ExtractDependencies extracts all resolver references from a resolver definition. If lookup is provided, it will use provider-specific ExtractDependencies functions when available. If lookup is nil, only generic extraction is performed. Explicit dependencies from DependsOn are always included and merged with auto-extracted dependencies.
func ExtractInferredDependencies ¶ added in v0.17.0
func ExtractInferredDependencies(r *Resolver, lookup DescriptorLookup) []string
ExtractInferredDependencies extracts only auto-inferred dependencies from value references (expr:, rslvr:, tmpl:) and when clauses, excluding explicit DependsOn entries. This is useful for detecting redundant dependsOn declarations.
func ExtractOptionalRefsFromValueRef ¶ added in v0.36.0
ExtractOptionalRefsFromValueRef collects resolver names that a ValueRef references via optional CEL access (_.?name, _[?"name"]), accumulating them into the provided optional set. Optional access is a CEL-only concept, so direct rslvr: references and Go-template (tmpl:) accessors -- which are always hard -- contribute nothing. Within a single CEL expression, a name also accessed with hard syntax is excluded (hard access dominates). Passing a nil ref or optional map is a no-op (optional must be non-nil to collect results).
func ExtractRefsFromValueRef ¶ added in v0.24.0
ExtractRefsFromValueRef extracts all resolver names referenced by a single ValueRef, accumulating them into the provided deps set. It handles direct resolver references, CEL expressions, Go templates, and nested literal values using the same AST-based logic the dependency graph uses. Passing a nil ref or deps map is a no-op (deps must be non-nil to collect results).
func ExtractRefsFromValueRefs ¶ added in v0.19.0
ExtractRefsFromValueRefs extracts all resolver names referenced by a set of ValueRef values. This is useful for determining which resolvers an action depends on based on its inputs map. The result is sorted for deterministic output.
func FormatDiffHuman ¶
func FormatDiffHuman(diff *SnapshotDiff) string
FormatDiffHuman formats the diff in human-readable format
func FormatDiffJSON ¶
func FormatDiffJSON(diff *SnapshotDiff) (string, error)
FormatDiffJSON formats the diff as JSON
func FormatDiffUnified ¶
func FormatDiffUnified(diff *SnapshotDiff) string
FormatDiffUnified formats the diff in unified diff format (similar to git diff)
func FormatMetricsSummary ¶
func FormatMetricsSummary(summary *MetricsSummary) string
FormatMetricsSummary formats the metrics summary for human-readable display
func GetMaxPhase ¶
func GetMaxPhase(phases []*PhaseGroup) int
GetMaxPhase returns the maximum phase number in the phase groups
func GetPhaseForResolver ¶
func GetPhaseForResolver(phases []*PhaseGroup, resolverName string) int
GetPhaseForResolver returns the phase number for a given resolver name
func IsAggregatedExecutionError ¶
IsAggregatedExecutionError checks if an error is an AggregatedExecutionError.
func IsCircularDependencyError ¶
IsCircularDependencyError checks if an error is a CircularDependencyError.
func IsExecutionError ¶
IsExecutionError checks if an error is an ExecutionError.
func IsForEachTypeError ¶
IsForEachTypeError checks if an error is a ForEachTypeError.
func IsTransitiveDependency ¶ added in v0.6.0
func IsTransitiveDependency(resolvers map[string]*Resolver, targetResolver, candidateName string) bool
IsTransitiveDependency checks if candidateName is a direct or transitive dependency of the targetResolver within the solution's resolver map. This is useful for filtering resolver graphs to show only relevant dependencies.
func IsTypeCoercionError ¶
IsTypeCoercionError checks if an error is a TypeCoercionError.
func IsValidationError ¶
IsValidationError checks if an error is an AggregatedValidationError.
func IsValueSizeError ¶
IsValueSizeError checks if an error is a ValueSizeError.
func RecordResolverExecution ¶
func RecordResolverExecution(resolverName string, result *ExecutionResult)
RecordResolverExecution records metrics for a completed resolver execution
func RedactError ¶
RedactError wraps an error with redaction if sensitive is true. The original error is preserved and can be accessed via errors.Unwrap.
func RedactMapValues ¶
RedactMapValues redacts all values in a map if sensitive is true. Keys are preserved, only values are replaced with [REDACTED].
func RedactSensitiveValues ¶
func RedactSensitiveValues(snapshot *Snapshot, resolvers []ResolverLike)
RedactSensitiveValues redacts sensitive values in the snapshot based on resolver-like objects
func RedactValue ¶
RedactValue returns [REDACTED] for any value if sensitive is true, otherwise returns the value unchanged. This is safe for use in logs, error messages, and JSON output.
func RegisterResolverMetrics ¶
func RegisterResolverMetrics()
RegisterResolverMetrics registers all resolver-related Prometheus metrics
func SaveSnapshot ¶
SaveSnapshot saves a snapshot to a JSON file
Types ¶
type AggregatedDeferredValidationError ¶ added in v0.34.0
type AggregatedDeferredValidationError struct {
Failures []DeferredValidationFailure `json:"failures" yaml:"failures" doc:"Per-resolver deferred validation failures, root-cause-first" minItems:"1"`
Suppressed []string `` /* 135-byte string literal not displayed */
}
AggregatedDeferredValidationError aggregates deferred (cross-resolver) validation failures across resolvers, ordered root-cause-first. Deferred validation runs after every resolver has resolved, so failures cannot be attributed to a single resolve phase; this error type carries per-resolver failure groups plus the set of rules suppressed because an upstream deferred validation already failed.
func (*AggregatedDeferredValidationError) Error ¶ added in v0.34.0
func (e *AggregatedDeferredValidationError) Error() string
Error implements the error interface.
func (*AggregatedDeferredValidationError) HasFailures ¶ added in v0.34.0
func (e *AggregatedDeferredValidationError) HasFailures() bool
HasFailures returns true if there are any deferred validation failures.
func (*AggregatedDeferredValidationError) Unwrap ¶ added in v0.34.0
func (e *AggregatedDeferredValidationError) Unwrap() error
Unwrap returns nil since this error aggregates multiple failures. Use errors.As with *ValidationFailure to inspect individual failures.
type AggregatedExecutionError ¶
type AggregatedExecutionError struct {
Errors []*FailedResolver `json:"errors" yaml:"errors" doc:"All errors encountered during execution" minItems:"1"`
SkippedCount int `json:"skippedCount" yaml:"skippedCount" doc:"Number of resolvers skipped due to failed dependencies" minimum:"0" example:"3"`
SkippedNames []string `json:"skippedNames" yaml:"skippedNames" doc:"Names of skipped resolvers"`
SucceededCount int `json:"succeededCount" yaml:"succeededCount" doc:"Number of resolvers that succeeded" minimum:"0" example:"5"`
}
AggregatedExecutionError represents multiple resolver errors collected during validate-all mode. This is used when the executor is configured to continue execution after failures.
func (*AggregatedExecutionError) Add ¶
func (e *AggregatedExecutionError) Add(resolverName string, phase int, err error)
Add adds a resolver error to the aggregated error.
func (*AggregatedExecutionError) AddSkipped ¶
func (e *AggregatedExecutionError) AddSkipped(resolverName string)
AddSkipped records that a resolver was skipped due to failed dependencies.
func (*AggregatedExecutionError) Error ¶
func (e *AggregatedExecutionError) Error() string
Error implements the error interface.
func (*AggregatedExecutionError) HasErrors ¶
func (e *AggregatedExecutionError) HasErrors() bool
HasErrors returns true if there are any errors.
func (*AggregatedExecutionError) IncrementSucceeded ¶
func (e *AggregatedExecutionError) IncrementSucceeded()
IncrementSucceeded increments the count of succeeded resolvers.
type AggregatedValidationError ¶
type AggregatedValidationError struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Name of the resolver that failed validation" example:"user-email"`
Value any `json:"-" yaml:"-" doc:"The value that failed validation"`
Failures []ValidationFailure `json:"failures" yaml:"failures" doc:"List of validation failures" minItems:"1"`
Sensitive bool `json:"sensitive,omitempty" yaml:"sensitive,omitempty" doc:"Whether the resolver value is sensitive"`
CustomMessage string `json:"customMessage,omitempty" yaml:"customMessage,omitempty" doc:"User-defined error message from messages.error"`
}
AggregatedValidationError represents validation failure with multiple messages. This collects all validation failures from a resolver's validate phase.
func (*AggregatedValidationError) AddFailure ¶
func (e *AggregatedValidationError) AddFailure(failure ValidationFailure)
AddFailure adds a validation failure to the error.
func (*AggregatedValidationError) Error ¶
func (e *AggregatedValidationError) Error() string
Error implements the error interface.
func (*AggregatedValidationError) HasFailures ¶
func (e *AggregatedValidationError) HasFailures() bool
HasFailures returns true if there are any validation failures.
func (*AggregatedValidationError) Unwrap ¶
func (e *AggregatedValidationError) Unwrap() error
Unwrap returns nil since this error aggregates multiple failures. Use errors.As with *ValidationFailure to check individual failures.
type AttemptDetail ¶
type AttemptDetail struct {
Provider string `json:"provider" yaml:"provider" doc:"Provider name" maxLength:"128" example:"http"`
Error string `json:"error" yaml:"error" doc:"Error message" maxLength:"4096" example:"connection refused"`
}
AttemptDetail contains details of a failed attempt
type BuildResult ¶ added in v0.7.0
type BuildResult struct {
Phases []*PhaseGroup `json:"phases" yaml:"phases" doc:"Execution phase groups"`
Plan PlanData `json:"plan" yaml:"plan" doc:"Pre-execution resolver topology snapshot"`
Deps map[string][]string `json:"-" yaml:"-" doc:"Effective dependency map (reusable by callers)"`
// DeferredWork lists resolvers with cross-resolver validation rules that must
// run in the post-resolution validation phase. Empty when no resolver has any
// deferred validation rules.
DeferredWork []DeferredValidationUnit `json:"-" yaml:"-" doc:"Deferred cross-resolver validation work"`
}
BuildResult is the output of BuildPhases, bundling the phase groups with the pre-execution plan topology so callers can inject __plan without re-computing deps.
func BuildPhases ¶
func BuildPhases(resolvers []*Resolver, lookup DescriptorLookup) (*BuildResult, error)
BuildPhases groups resolvers into execution phases based on dependencies. Phase numbers are 1-based, with phase 1 being root resolvers (no dependencies). If lookup is provided, provider-specific ExtractDependencies functions will be used when available for more accurate dependency detection. The returned BuildResult includes both the phase groups and PlanData — a static topology snapshot that can be injected as __plan before execution begins.
func BuildPhasesWithCalls ¶ added in v0.34.0
func BuildPhasesWithCalls(resolvers []*Resolver, lookup DescriptorLookup, calls map[string]*spec.Call) (*BuildResult, error)
BuildPhasesWithCalls is BuildPhases with awareness of reusable call definitions. Call definitions are strictly isolated (their inputs may not reference solution resolvers), so invoking a call contributes no extra dependencies; the calls map is threaded through for signature parity and future use.
type CircularDependencyError ¶
type CircularDependencyError struct {
Cycle []string `` /* 144-byte string literal not displayed */
}
CircularDependencyError represents a cycle detected in resolver dependencies.
func NewCircularDependencyError ¶
func NewCircularDependencyError(cycle []string) *CircularDependencyError
NewCircularDependencyError creates a new CircularDependencyError from a cycle path.
func (*CircularDependencyError) Error ¶
func (e *CircularDependencyError) Error() string
Error implements the error interface.
type Condition ¶
type Condition struct {
Expr *celexp.Expression `json:"expr" yaml:"expr" doc:"CEL expression that must evaluate to boolean" example:"_.environment == 'prod'"`
}
Condition is a resolver-specific condition type with custom YAML/JSON unmarshalling. Unlike spec.Condition, this type only wraps the expr field, keeping backward compatibility with existing resolver YAML files.
Supported YAML/JSON forms:
- String shorthand: when: "_.environment == 'prod'"
- Boolean literal: when: true / when: false
- Object form: when: { expr: "_.environment == 'prod'" }
- Expression alias: when: { expression: "_.environment == 'prod'" }
- Null: when: null (treated as unset, nil Expr)
func (*Condition) UnmarshalJSON ¶ added in v0.8.0
UnmarshalJSON supports shorthand forms for conditions.
- string → treated as a CEL expression
- bool → converted to literal "true" or "false" CEL expression
- object → standard {expr: "..."} form
func (*Condition) UnmarshalYAML ¶ added in v0.8.0
UnmarshalYAML supports shorthand forms for conditions.
- string → treated as a CEL expression
- bool → converted to literal "true" or "false" CEL expression
- object → standard {expr: "..."} form
type Config ¶
type Config struct {
MaxValueSizeBytes int64 `` /* 152-byte string literal not displayed */
WarnValueSizeBytes int64 `` /* 153-byte string literal not displayed */
MaxConcurrency int `` /* 164-byte string literal not displayed */
PhaseTimeout time.Duration `` /* 139-byte string literal not displayed */
}
Config contains global resolver configuration
type ConfigInput ¶
type ConfigInput struct {
// Timeout is the default timeout per resolver execution
Timeout time.Duration `json:"timeout" yaml:"timeout" doc:"Default timeout per resolver execution"`
// PhaseTimeout is the maximum time for each resolution phase
PhaseTimeout time.Duration `json:"phaseTimeout" yaml:"phaseTimeout" doc:"Maximum time for each resolution phase"`
// MaxConcurrency is the maximum concurrent resolvers per phase (0 = unlimited)
MaxConcurrency int `` /* 132-byte string literal not displayed */
// WarnValueSize is the warn threshold in bytes (0 = disabled)
WarnValueSize int64 `json:"warnValueSize" yaml:"warnValueSize" doc:"Warn threshold in bytes (0 = disabled)" example:"1048576"`
// MaxValueSize is the max value size in bytes (0 = disabled)
MaxValueSize int64 `json:"maxValueSize" yaml:"maxValueSize" doc:"Max value size in bytes (0 = disabled)" example:"10485760"`
// ValidateAll enables collecting all errors instead of stopping at first
ValidateAll bool `json:"validateAll" yaml:"validateAll" doc:"Collect all validation errors instead of stopping at first"`
}
ConfigInput holds the configuration values for resolver executor initialization. This mirrors config.ResolverConfig but avoids circular dependencies.
type Context ¶
type Context struct {
// contains filtered or unexported fields
}
Context is a thread-safe storage for resolver results and execution metadata
func FromContext ¶
FromContext retrieves resolver context from a Go context
func (*Context) DeferredValidation ¶ added in v0.34.0
func (c *Context) DeferredValidation() *DeferredValidationSummary
DeferredValidation returns the deferred validation summary, or nil if the deferred validation phase did not run.
func (*Context) GetAllResults ¶
func (c *Context) GetAllResults() map[string]*ExecutionResult
GetAllResults returns all resolver execution results with metadata Used for observability, logging, and metrics
func (*Context) GetResult ¶
func (c *Context) GetResult(name string) (*ExecutionResult, bool)
GetResult retrieves the full resolver execution result including metadata
func (*Context) SetDeferredValidation ¶ added in v0.34.0
func (c *Context) SetDeferredValidation(summary *DeferredValidationSummary)
SetDeferredValidation stores the deferred (cross-resolver) validation summary.
func (*Context) SetResult ¶
func (c *Context) SetResult(name string, result *ExecutionResult)
SetResult stores a resolver result with full execution metadata
type DeferredReportingPlan ¶ added in v0.34.0
type DeferredReportingPlan struct {
// Order lists the resolver names owning deferred units in root-cause-first
// order: a resolver whose deferred rules reference other resolvers is reported
// after those referenced resolvers, so upstream failures surface first and can
// suppress cascaded failures.
Order []string
// Cycles lists strongly connected components with more than one member. These
// are informational: a cycle in the reporting graph is not an error (deferred
// rules only read final values), but surfacing it helps authors understand why
// ordering within the component is name-sorted rather than dependency-driven.
Cycles [][]string
}
DeferredReportingPlan describes the order in which deferred (cross-resolver) validation results should be evaluated and reported.
The reporting graph is derived from DeferredValidationUnit.DependsOn edges (which resolver a rule references). Unlike the resolution DAG, this graph is used only for ordering and reporting -- it MAY contain cycles (two resolvers can validate against each other). Cycles are tolerated: they are condensed into strongly connected components so a deterministic, root-cause-first order can still be produced.
type DeferredValidationFailure ¶ added in v0.34.0
type DeferredValidationFailure struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Name of the resolver whose deferred validation failed" example:"checker"`
Failures []ValidationFailure `json:"failures" yaml:"failures" doc:"List of deferred validation failures" minItems:"1"`
Sensitive bool `json:"sensitive,omitempty" yaml:"sensitive,omitempty" doc:"Whether the resolver value is sensitive"`
}
DeferredValidationFailure holds the deferred (cross-resolver) validation failures for a single resolver. It reuses ValidationFailure for each failing rule so the inline and deferred paths report failures identically.
type DeferredValidationSummary ¶ added in v0.34.0
type DeferredValidationSummary struct {
// Evaluated is the number of deferred rules whose provider was invoked.
Evaluated int
// Failed is the number of deferred rules that failed.
Failed int
// Skipped is the number of deferred rules that did not run (owning resolver
// had no value, or a phase/rule when condition evaluated false).
Skipped int
// Results holds the per-resolver failures, ordered root-cause-first.
Results []DeferredValidationFailure
// Suppressed lists resolvers whose deferred rules were suppressed because a
// referenced resolver already failed its own deferred validation.
Suppressed []string
// Cycles lists cross-validation cycles detected in the reporting graph. These
// are informational (tolerated), not errors.
Cycles [][]string
}
DeferredValidationSummary reports the outcome of the post-resolution deferred (cross-resolver) validation phase. It is attached to the execution context so collect-errors-mode callers (for example `run resolver`) can inspect and gate on deferred validation without treating it as a fatal error.
func DeferredValidationResultFromContext ¶ added in v0.34.0
func DeferredValidationResultFromContext(ctx context.Context) (*DeferredValidationSummary, bool)
DeferredValidationResultFromContext returns the deferred validation summary attached to ctx by Execute, if any. Callers use it to gate state persistence and actions on deferred validation results in non-fatal modes.
func (*DeferredValidationSummary) HasFailures ¶ added in v0.34.0
func (s *DeferredValidationSummary) HasFailures() bool
HasFailures reports whether any deferred validation rule failed.
type DeferredValidationUnit ¶ added in v0.34.0
type DeferredValidationUnit struct {
// ResolverName is the resolver that owns the deferred rules.
ResolverName string
// RuleIndices are indices into the resolver's Validate.With slice identifying
// which rules are deferred. Preserves declaration order.
RuleIndices []int
// DependsOn is the sorted set of foreign resolvers referenced by the deferred
// rules. Used only to order and report deferred validation results -- these are
// never resolution-graph edges.
DependsOn []string
// PhaseWhenDeferred indicates the phase-level validate.when referenced a
// foreign resolver, forcing every rule in the block to defer.
PhaseWhenDeferred bool
}
DeferredValidationUnit describes the deferred (cross-resolver) validation rules for a single resolver. These rules reference other resolvers and are excluded from the resolution DAG; they run in a dedicated post-resolution validation phase once every resolver has resolved.
type DescriptorLookup ¶
type DescriptorLookup func(providerName string) *provider.Descriptor
DescriptorLookup is a function that retrieves a provider descriptor by name. Used during dependency extraction to allow providers to participate in extracting dependencies from their inputs.
type DiffOptions ¶
type DiffOptions struct {
IgnoreUnchanged bool `json:"ignoreUnchanged" yaml:"ignoreUnchanged" doc:"Whether to omit unchanged resolvers from output"`
IgnoreFields []string `` /* 142-byte string literal not displayed */
ResolverFilter string `` /* 146-byte string literal not displayed */
}
DiffOptions provides options for diff comparison
type DiffSummary ¶
type DiffSummary struct {
TotalResolvers int `json:"totalResolvers" yaml:"totalResolvers" doc:"Total number of resolvers compared" maximum:"10000" example:"20"`
Added int `json:"added" yaml:"added" doc:"Number of resolvers added" maximum:"10000" example:"2"`
Removed int `json:"removed" yaml:"removed" doc:"Number of resolvers removed" maximum:"10000" example:"1"`
Modified int `json:"modified" yaml:"modified" doc:"Number of resolvers modified" maximum:"10000" example:"3"`
Unchanged int `json:"unchanged" yaml:"unchanged" doc:"Number of resolvers unchanged" maximum:"10000" example:"14"`
}
DiffSummary provides a summary of all changes
type DiffType ¶
type DiffType string
DiffType represents the type of difference found
const ( DiffTypeAdded DiffType = "added" // Resolver exists in after but not before DiffTypeRemoved DiffType = "removed" // Resolver exists in before but not after DiffTypeModified DiffType = "modified" // Resolver exists in both but values differ DiffTypeUnchanged DiffType = "unchanged" // Resolver exists in both and is identical )
type ErrorBehavior ¶
type ErrorBehavior = spec.OnErrorBehavior
ErrorBehavior is an alias to spec.OnErrorBehavior for backward compatibility. New code should use spec.OnErrorBehavior directly.
type ExecutionError ¶
type ExecutionError struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Name of the resolver that failed" example:"my-resolver"`
Phase string `json:"phase" yaml:"phase" doc:"Execution phase where failure occurred" enum:"resolve,transform,validate" example:"resolve"`
Step int `json:"step" yaml:"step" doc:"Step number within the phase (0-indexed)" minimum:"0" example:"0"`
Provider string `json:"provider" yaml:"provider" doc:"Provider name that failed" example:"http"`
Cause error `json:"-" yaml:"-" doc:"Underlying error that caused the failure"`
CustomMessage string `json:"customMessage,omitempty" yaml:"customMessage,omitempty" doc:"User-defined error message from messages.error"`
}
ExecutionError represents an error during resolver execution with context about which resolver, phase, step, and provider were involved.
func NewExecutionError ¶
func NewExecutionError(resolverName, phase, provider string, step int, cause error) *ExecutionError
NewExecutionError creates a new ExecutionError with the given parameters.
func (*ExecutionError) Error ¶
func (e *ExecutionError) Error() string
Error implements the error interface.
func (*ExecutionError) Unwrap ¶
func (e *ExecutionError) Unwrap() error
Unwrap returns the underlying cause for use with errors.Is and errors.As.
type ExecutionResult ¶
type ExecutionResult struct {
// Value is the actual resolved value
Value any `json:"value" yaml:"value" doc:"The resolved value"`
// Metadata (internal use only, not accessible in CEL)
Status ExecutionStatus `json:"status" yaml:"status" doc:"Execution status" example:"success"`
Phase int `json:"phase" yaml:"phase" doc:"Execution phase number (1-based)" example:"1"`
TotalDuration time.Duration `json:"totalDuration" yaml:"totalDuration" doc:"Total execution time across all phases" example:"250ms"`
StartTime time.Time `json:"startTime" yaml:"startTime" doc:"When resolver execution started"`
EndTime time.Time `json:"endTime" yaml:"endTime" doc:"When resolver execution ended"`
Error error `json:"error,omitempty" yaml:"error,omitempty" doc:"Error if failed"`
PhaseMetrics []PhaseMetrics `json:"phaseMetrics" yaml:"phaseMetrics" doc:"Per-phase timing" maxItems:"3"`
ProviderCallCount int `json:"providerCallCount" yaml:"providerCallCount" doc:"Number of provider calls made" example:"2"`
ValueSizeBytes int64 `json:"valueSizeBytes" yaml:"valueSizeBytes" doc:"Size of the value in bytes" example:"1024"`
DependencyCount int `json:"dependencyCount" yaml:"dependencyCount" doc:"Number of dependencies" example:"3"`
FailedAttempts []ProviderAttempt `json:"failedAttempts,omitempty" yaml:"failedAttempts,omitempty" doc:"Failed provider attempts (for debugging)" maxItems:"10"`
}
ExecutionResult contains both the value and execution metadata
type ExecutionStatus ¶
type ExecutionStatus string
ExecutionStatus represents the execution status of a resolver
const ( ExecutionStatusSuccess ExecutionStatus = "success" ExecutionStatusFailed ExecutionStatus = "failed" ExecutionStatusSkipped ExecutionStatus = "skipped" )
type Executor ¶
type Executor struct {
// contains filtered or unexported fields
}
Executor executes resolvers in phases with concurrency control
func NewExecutor ¶
func NewExecutor(registry RegistryInterface, opts ...ExecutorOption) *Executor
NewExecutor creates a new resolver executor
type ExecutorOption ¶
type ExecutorOption func(*Executor)
ExecutorOption is a functional option for configuring the Executor
func OptionsFromAppConfig ¶
func OptionsFromAppConfig(cfg ConfigInput) []ExecutorOption
NewExecutorFromAppConfig creates a new resolver executor using app configuration. CLI flags can override these defaults using the returned executor options.
Example:
cfg := resolver.ResolverConfigInput{
Timeout: 30 * time.Second,
PhaseTimeout: 5 * time.Minute,
MaxConcurrency: 0,
}
opts := resolver.OptionsFromAppConfig(cfg)
executor := resolver.NewExecutor(registry, opts...)
func WithCalls ¶ added in v0.34.0
func WithCalls(calls map[string]*spec.Call) ExecutorOption
WithCalls registers the solution's reusable call definitions (spec.calls) so that resolve/transform/validate steps invoking a definition via call + args can be expanded and executed.
func WithDefaultTimeout ¶
func WithDefaultTimeout(timeout time.Duration) ExecutorOption
WithDefaultTimeout sets the default timeout for individual resolver execution
func WithDeferredValidation ¶ added in v0.34.0
func WithDeferredValidation(enabled bool) ExecutorOption
WithDeferredValidation enables or disables the post-resolution deferred validation phase, which evaluates cross-resolver validation rules (rules that reference resolvers other than their owner) after every resolver has resolved. It is enabled by default; disable it to evaluate only inline (self-only) validations. Disabling has no effect when validation is already skipped via WithSkipValidation or WithSkipTransform.
func WithMaxConcurrency ¶
func WithMaxConcurrency(maxConcurrency int) ExecutorOption
WithMaxConcurrency sets the maximum number of resolvers that can execute concurrently per phase
func WithMaxValueSize ¶
func WithMaxValueSize(bytes int64) ExecutorOption
WithMaxValueSize sets the maximum allowed value size in bytes Values exceeding this limit will cause resolver execution to fail Set to 0 to disable the limit
func WithMockedResolvers ¶ added in v0.11.0
func WithMockedResolvers(mocks map[string]any) ExecutorOption
WithMockedResolvers pre-populates resolver values so that the corresponding resolvers skip execution entirely and return the mocked value. This enables functional testing of downstream resolvers and CEL expressions without hitting external APIs or services.
func WithNonFatalValidation ¶ added in v0.27.0
func WithNonFatalValidation(enabled bool) ExecutorOption
WithNonFatalValidation treats validation-rule failures as non-fatal: execution continues and all errors are collected (like validate-all), but a resolver that fails only a validation rule still produces a usable value, so its dependents are NOT skipped. Resolve and transform failures remain fatal and still skip dependents. This powers `run resolver`, which must surface a full, inspectable view of the data layer even when business-rule validations fail.
func WithPhaseTimeout ¶
func WithPhaseTimeout(timeout time.Duration) ExecutorOption
WithPhaseTimeout sets the maximum time allowed for each phase to complete
func WithProgressCallback ¶
func WithProgressCallback(callback ProgressCallback) ExecutorOption
WithProgressCallback sets a callback for receiving execution progress events. This enables real-time progress reporting during resolver execution.
func WithSkipTransform ¶ added in v0.2.0
func WithSkipTransform(enabled bool) ExecutorOption
WithSkipTransform disables the transform and validation phases for all resolvers. When enabled, resolvers will execute only the resolve phase, returning the raw resolved value without any transformations or validations applied.
func WithSkipValidation ¶
func WithSkipValidation(enabled bool) ExecutorOption
WithSkipValidation disables the validation phase for all resolvers. When enabled, resolvers will execute their resolve and transform phases but skip validation entirely.
func WithValidateAll ¶
func WithValidateAll(enabled bool) ExecutorOption
WithValidateAll enables validate-all mode where execution continues even when resolvers fail, collecting all errors instead of stopping at the first error. Resolvers that depend on failed resolvers will be skipped.
func WithWarnValueSize ¶
func WithWarnValueSize(bytes int64) ExecutorOption
WithWarnValueSize sets the size threshold for warning about large values Set to 0 to disable warnings
type FailedAttemptSummary ¶
type FailedAttemptSummary struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Resolver name" maxLength:"256" example:"api-data"`
AttemptCount int `json:"attemptCount" yaml:"attemptCount" doc:"Number of failed attempts" maximum:"100" example:"2"`
Attempts []AttemptDetail `json:"attempts" yaml:"attempts" doc:"Details of each failed attempt" maxItems:"100"`
}
FailedAttemptSummary summarizes failed attempts for a resolver
type FailedResolver ¶
type FailedResolver struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Name of the resolver that failed" example:"my-resolver"`
Phase int `json:"phase" yaml:"phase" doc:"Phase number where the error occurred" minimum:"1" example:"1"`
Err error `json:"-" yaml:"-" doc:"The underlying error"`
ErrMessage string `json:"error" yaml:"error" doc:"Error message" maxLength:"2000" example:"validation failed: value must be positive"`
}
FailedResolver represents an error from a specific resolver with context. Used within AggregatedExecutionError for validate-all mode.
func (*FailedResolver) Error ¶
func (e *FailedResolver) Error() string
Error implements the error interface.
func (*FailedResolver) Unwrap ¶
func (e *FailedResolver) Unwrap() error
Unwrap returns the underlying error for errors.Is/As support.
type FailureSummary ¶
type FailureSummary struct {
Name string `json:"name" yaml:"name" doc:"Resolver name" maxLength:"256" example:"api-data"`
Phase int `json:"phase" yaml:"phase" doc:"Phase where failure occurred" maximum:"100" example:"1"`
Error string `json:"error" yaml:"error" doc:"Error message" maxLength:"4096" example:"timeout"`
}
FailureSummary contains information about a failed resolver
type FieldChange ¶
type FieldChange struct {
Field string `json:"field" yaml:"field" doc:"Field name that changed" maxLength:"128" example:"value"`
Before any `json:"before" yaml:"before" doc:"Value before change"`
After any `json:"after" yaml:"after" doc:"Value after change"`
}
FieldChange represents a change in a specific field
type ForEachClause ¶
type ForEachClause = spec.ForEachClause
ForEachClause is an alias to spec.ForEachClause for backward compatibility.
type ForEachIterationResult ¶
type ForEachIterationResult struct {
Index int `json:"index" yaml:"index" doc:"Index of the iteration" minimum:"0" example:"1"`
Data any `json:"data,omitempty" yaml:"data,omitempty" doc:"Result data if successful"`
Error string `json:"error,omitempty" yaml:"error,omitempty" doc:"Error message if failed" maxLength:"1000"`
Item any `json:"item,omitempty" yaml:"item,omitempty" doc:"The item that was processed"`
}
ForEachIterationResult represents the result of a single forEach iteration. Used when onError: continue allows partial results with error metadata.
type ForEachTypeError ¶
type ForEachTypeError struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Name of the resolver" example:"regionConfigs"`
Step int `json:"step" yaml:"step" doc:"Transform step number (0-indexed)" minimum:"0" example:"0"`
ActualType string `json:"actualType" yaml:"actualType" doc:"Actual type received" example:"string"`
}
ForEachTypeError represents an error when forEach input is not an array.
func (*ForEachTypeError) Error ¶
func (e *ForEachTypeError) Error() string
Error implements the error interface.
type Graph ¶
type Graph struct {
Nodes []*GraphNode `json:"nodes" yaml:"nodes" doc:"Graph nodes" maxItems:"1000"`
Edges []*GraphEdge `json:"edges" yaml:"edges" doc:"Graph edges" maxItems:"10000"`
Phases []*PhaseInfo `json:"phases" yaml:"phases" doc:"Phase information" maxItems:"100"`
Stats *GraphStats `json:"stats" yaml:"stats" doc:"Graph statistics"`
Diagrams *GraphDiagrams `json:"diagrams" yaml:"diagrams" doc:"Pre-rendered diagram representations"`
}
Graph represents the complete resolver dependency graph
func BuildGraph ¶
func BuildGraph(resolvers []*Resolver, lookup DescriptorLookup) (*Graph, error)
BuildGraph creates a Graph from resolvers. If lookup is provided, provider-specific ExtractDependencies functions will be used when available for more accurate dependency detection.
func (*Graph) RenderASCII ¶
RenderASCII generates ASCII art representation
func (*Graph) RenderDiagrams ¶ added in v0.2.0
RenderDiagrams pre-renders all diagram representations and stores them in the Diagrams field. This allows diagram strings to appear in JSON/YAML output without requiring an io.Writer at consumption time.
type GraphDependency ¶
type GraphDependency struct {
Resolver string `json:"resolver" yaml:"resolver" doc:"Target resolver name" maxLength:"256" example:"auth-token"`
Field string `json:"field" yaml:"field" doc:"Field name in reference" maxLength:"128" example:"value"`
}
GraphDependency represents a dependency edge
type GraphDiagrams ¶ added in v0.2.0
type GraphDiagrams struct {
ASCII string `json:"ascii" yaml:"ascii" doc:"ASCII art representation of the graph" maxLength:"65536"`
DOT string `json:"dot" yaml:"dot" doc:"Graphviz DOT format representation" maxLength:"65536"`
Mermaid string `json:"mermaid" yaml:"mermaid" doc:"Mermaid.js diagram representation" maxLength:"65536"`
}
GraphDiagrams contains pre-rendered diagram representations of the dependency graph.
type GraphEdge ¶
type GraphEdge struct {
From string `json:"from" yaml:"from" doc:"Source resolver name" maxLength:"256" example:"api-data"`
To string `json:"to" yaml:"to" doc:"Target resolver name" maxLength:"256" example:"auth-token"`
Label string `json:"label" yaml:"label" doc:"Edge label" maxLength:"256" example:"depends_on"`
}
GraphEdge represents a directed edge
type GraphNode ¶
type GraphNode struct {
Name string `json:"id" yaml:"id" doc:"Resolver name" maxLength:"256" example:"api-data"`
Type Type `json:"type" yaml:"type" doc:"Resolver type" maxLength:"64" example:"standard"`
Phase int `json:"phase" yaml:"phase" doc:"Execution phase (1-based)" maximum:"100" example:"1"`
Conditional bool `json:"conditional" yaml:"conditional" doc:"Whether resolver has conditional execution"`
Dependencies []GraphDependency `json:"dependencies" yaml:"dependencies" doc:"List of dependencies" maxItems:"100"`
}
GraphNode represents a resolver node in the dependency graph
type GraphStats ¶
type GraphStats struct {
TotalResolvers int `json:"totalResolvers" yaml:"totalResolvers" doc:"Total number of resolvers" maximum:"10000" example:"20"`
TotalPhases int `json:"totalPhases" yaml:"totalPhases" doc:"Total number of execution phases" maximum:"100" example:"3"`
MaxParallelism int `json:"maxParallelism" yaml:"maxParallelism" doc:"Maximum parallelism across all phases" maximum:"1000" example:"4"`
AvgDependencies float64 `json:"avgDependencies" yaml:"avgDependencies" doc:"Average number of dependencies per resolver"`
CriticalPath []string `json:"criticalPath" yaml:"criticalPath" doc:"Longest dependency chain in the graph" maxItems:"100"`
CriticalDepth int `json:"criticalDepth" yaml:"criticalDepth" doc:"Length of the critical path" maximum:"100" example:"5"`
}
GraphStats contains graph statistics
type IterationContext ¶
type IterationContext = spec.IterationContext
IterationContext is an alias to spec.IterationContext for backward compatibility. It holds the context for forEach iteration variables.
type Messages ¶ added in v0.6.0
type Messages struct {
// Error is shown when the resolver fails (resolve, transform, or validate phase).
// Supports static strings, CEL expressions (expr:), and Go templates (tmpl:).
// The resolver data map is available as _ and the error message as __error.
Error *ValueRef `json:"error,omitempty" yaml:"error,omitempty" doc:"Custom message on resolver failure"`
}
Messages holds user-defined messages displayed on resolver outcomes.
type MetricsSummary ¶
type MetricsSummary struct {
TotalResolvers int `json:"totalResolvers" yaml:"totalResolvers" doc:"Total number of resolvers executed" maximum:"10000" example:"20"`
SuccessCount int `json:"successCount" yaml:"successCount" doc:"Number of successful resolvers" maximum:"10000" example:"18"`
FailedCount int `json:"failedCount" yaml:"failedCount" doc:"Number of failed resolvers" maximum:"10000" example:"1"`
SkippedCount int `json:"skippedCount" yaml:"skippedCount" doc:"Number of skipped resolvers" maximum:"10000" example:"1"`
TotalDuration time.Duration `json:"totalDuration" yaml:"totalDuration" doc:"Total execution time"`
PhaseCount int `json:"phaseCount" yaml:"phaseCount" doc:"Number of execution phases" maximum:"100" example:"3"`
SlowestResolvers []ResolverMetric `json:"slowestResolvers,omitempty" yaml:"slowestResolvers,omitempty" doc:"Top resolvers by execution time" maxItems:"20"`
LargestValues []ResolverMetric `json:"largestValues,omitempty" yaml:"largestValues,omitempty" doc:"Top resolvers by value size" maxItems:"20"`
FailedAttempts []FailedAttemptSummary `json:"failedAttempts,omitempty" yaml:"failedAttempts,omitempty" doc:"Resolvers with failed provider attempts" maxItems:"100"`
Failures []FailureSummary `json:"failures,omitempty" yaml:"failures,omitempty" doc:"Failed resolver details" maxItems:"100"`
}
MetricsSummary contains aggregated metrics for display
func BuildMetricsSummary ¶
func BuildMetricsSummary(results map[string]*ExecutionResult, phaseCount int) *MetricsSummary
BuildMetricsSummary creates a metrics summary from execution results
type PhaseGroup ¶
type PhaseGroup struct {
Phase int `json:"phase" yaml:"phase" doc:"Phase number (1-based)" minimum:"1"`
Resolvers []*Resolver `json:"resolvers" yaml:"resolvers" doc:"Resolvers in this phase" minItems:"1"`
}
PhaseGroup represents a group of resolvers that can execute concurrently
type PhaseInfo ¶
type PhaseInfo struct {
Phase int `json:"phase" yaml:"phase" doc:"Phase number (1-based)" maximum:"100" example:"1"`
Resolvers []string `json:"resolvers" yaml:"resolvers" doc:"Resolver names in this phase" maxItems:"1000"`
Parallelism int `json:"parallelism" yaml:"parallelism" doc:"Number of resolvers that can execute in parallel" maximum:"1000" example:"4"`
}
PhaseInfo contains information about a phase
type PhaseMetrics ¶
type PhaseMetrics struct {
Phase string `json:"phase" yaml:"phase" doc:"Phase name (resolve, transform, validate)" example:"resolve"`
Duration time.Duration `json:"duration" yaml:"duration" doc:"Time spent in this phase" example:"100ms"`
Started time.Time `json:"started" yaml:"started" doc:"When phase started"`
Ended time.Time `json:"ended" yaml:"ended" doc:"When phase ended"`
}
PhaseMetrics contains timing information for a single phase
type PhaseTimeoutError ¶
type PhaseTimeoutError struct {
Phase int `json:"phase" yaml:"phase" doc:"Phase number that timed out" minimum:"1" example:"1"`
ResolversWaiting []string `json:"resolversWaiting" yaml:"resolversWaiting" doc:"Resolvers that were still waiting when timeout occurred"`
}
PhaseTimeoutError represents a timeout during phase execution.
func (*PhaseTimeoutError) Error ¶
func (e *PhaseTimeoutError) Error() string
Error implements the error interface.
type Plan ¶ added in v0.7.0
type Plan struct {
Phase int `json:"phase" yaml:"phase" doc:"Execution phase number (1-based)" minimum:"1"`
DependsOn []string `json:"dependsOn" yaml:"dependsOn" doc:"Effective dependencies after provider extraction" maxItems:"1000"`
DependencyCount int `json:"dependencyCount" yaml:"dependencyCount" doc:"Number of effective dependencies" minimum:"0"`
}
Plan holds pre-execution static topology data for a single resolver. It is populated after DAG construction and before any resolver executes.
type PlanData ¶ added in v0.7.0
PlanData is a pre-execution snapshot of resolver topology, keyed by resolver name. It is injected into the resolver context as __plan before any resolver executes, making topology data available in when conditions and provider inputs.
type ProgressCallback ¶
type ProgressCallback interface {
// OnPhaseStart is called when a new execution phase begins
OnPhaseStart(phaseNum int, resolverNames []string)
// OnResolverComplete is called when a resolver completes successfully.
// elapsed is the pure execution time of the resolver.
OnResolverComplete(resolverName string, elapsed time.Duration)
// OnResolverFailed is called when a resolver fails
OnResolverFailed(resolverName string, err error)
// OnResolverSkipped is called when a resolver is skipped due to when condition
OnResolverSkipped(resolverName string)
}
ProgressCallback is an interface for receiving execution progress events. Implementations can use this to display progress bars, log events, etc.
type ProviderAttempt ¶
type ProviderAttempt struct {
Provider string `json:"provider" yaml:"provider" doc:"Provider name" example:"http"`
Phase string `json:"phase" yaml:"phase" doc:"Phase where provider was called" example:"resolve"`
Error string `json:"error,omitempty" yaml:"error,omitempty" doc:"Error message if failed" maxLength:"500"`
Duration time.Duration `json:"duration" yaml:"duration" doc:"Time spent in this attempt" example:"50ms"`
OnError string `json:"onError,omitempty" yaml:"onError,omitempty" doc:"Error handling behavior" example:"continue"`
Timestamp time.Time `json:"timestamp" yaml:"timestamp" doc:"When the attempt occurred"`
SourceStep int `json:"sourceStep" yaml:"sourceStep" doc:"Source/step index in phase (0-based)" example:"0"`
}
ProviderAttempt records a single provider execution attempt
type ProviderSource ¶
type ProviderSource struct {
spec.CallRef `yaml:",inline"`
Provider string `` /* 274-byte string literal not displayed */
Inputs map[string]*ValueRef `json:"inputs,omitempty" yaml:"inputs,omitempty" doc:"Provider inputs" required:"false"`
When *Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Source-level condition"`
ContinueOnError *Condition `` /* 337-byte string literal not displayed */
OnError ErrorBehavior `` /* 321-byte string literal not displayed */
ForEach *ForEachClause `` /* 162-byte string literal not displayed */
}
ProviderSource represents a single source in the resolve phase
type ProviderTransform ¶
type ProviderTransform struct {
spec.CallRef `yaml:",inline"`
Provider string `` /* 268-byte string literal not displayed */
Inputs map[string]*ValueRef `json:"inputs,omitempty" yaml:"inputs,omitempty" doc:"Provider inputs" required:"false"`
When *Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Step-level condition"`
ContinueOnError *Condition `` /* 330-byte string literal not displayed */
OnError ErrorBehavior `` /* 230-byte string literal not displayed */
ForEach *ForEachClause `json:"forEach,omitempty" yaml:"forEach,omitempty" doc:"Iterate over array, executing provider for each element"`
}
ProviderTransform represents a single transform step
type ProviderValidation ¶
type ProviderValidation struct {
spec.CallRef `yaml:",inline"`
Provider string `` /* 275-byte string literal not displayed */
Inputs map[string]*ValueRef `json:"inputs,omitempty" yaml:"inputs,omitempty" doc:"Provider inputs" required:"false"`
When *Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Rule-level condition; the rule is skipped when this evaluates to false"`
Message *ValueRef `json:"message,omitempty" yaml:"message,omitempty" doc:"Error message on validation failure"`
}
ProviderValidation represents a single validation rule
type RedactedError ¶
type RedactedError struct {
Original error `json:"-" yaml:"-" doc:"Original unredacted error"`
Redacted string `json:"error" yaml:"error" doc:"Redacted error message safe for display" maxLength:"100" example:"[REDACTED]"`
}
RedactedError wraps an error to provide a redacted version for sensitive contexts.
func NewRedactedError ¶
func NewRedactedError(original error) *RedactedError
NewRedactedError creates a new RedactedError.
func (*RedactedError) Error ¶
func (e *RedactedError) Error() string
Error returns the redacted error message.
func (*RedactedError) Unwrap ¶
func (e *RedactedError) Unwrap() error
Unwrap returns the original error for privileged access.
type RegistryInterface ¶
type RegistryInterface interface {
Register(p provider.Provider) error
Get(name string) (provider.Provider, error)
List() []provider.Provider
// DescriptorLookup returns a function that looks up provider descriptors by name.
// Returns nil if the registry does not support descriptor lookup.
DescriptorLookup() DescriptorLookup
}
type ResolvePhase ¶
type ResolvePhase struct {
With []ProviderSource `json:"with" yaml:"with" doc:"Ordered list of value sources" minItems:"1" maxItems:"200"`
Until *Condition `json:"until,omitempty" yaml:"until,omitempty" doc:"Stop condition (default: first non-null)"`
When *Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Phase-level condition"`
}
ResolvePhase defines how to obtain an initial value
type Resolver ¶
type Resolver struct {
// Metadata
Name string `` /* 233-byte string literal not displayed */
Description string `` /* 159-byte string literal not displayed */
DisplayName string `json:"displayName,omitempty" yaml:"displayName,omitempty" doc:"Display name for UI" maxLength:"80" example:"Environment"`
Sensitive bool `` /* 191-byte string literal not displayed */
Internal bool `` /* 153-byte string literal not displayed */
Explicit bool `json:"explicit,omitempty" yaml:"explicit,omitempty" doc:"If true, resolver only runs when explicitly named on the CLI"`
Example any `json:"example,omitempty" yaml:"example,omitempty" doc:"Example value for documentation"`
// Type declaration
Type Type `json:"type,omitempty" yaml:"type,omitempty" doc:"Expected type of the resolved value" example:"string"`
// Conditional execution
When *Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Condition for executing this resolver"`
// Explicit dependencies
DependsOn []string `` /* 187-byte string literal not displayed */
// Timeout
Timeout *time.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty" doc:"Maximum execution time (default: 30s)" example:"30s"`
// Immutable locks the resolver's value in state after first execution. On subsequent
// runs, the resolver still executes but its value is compared against the stored value.
// If the values differ, execution fails with an error. Use this for non-deterministic
// values (e.g., UUIDs) that must remain stable across runs. Requires the solution to
// have a state block configured and enabled. Setting Immutable implies Persist.
Immutable bool `json:"immutable,omitempty" yaml:"immutable,omitempty" doc:"Lock resolver value in state after first execution" example:"true"`
// Persist records the resolver's value in state after each successful run so it can be
// read back on a later run via the state provider. Unlike Immutable, the value is not
// locked or verified -- it is overwritten with the latest value every run. Persistence
// does not affect replay, does not skip execution, and does not feed the value back into
// resolver inputs automatically. Requires the solution to have a state block configured
// and enabled.
Persist bool `` /* 159-byte string literal not displayed */
// Phases
Resolve *ResolvePhase `json:"resolve" yaml:"resolve" doc:"Value resolution phase"`
Transform *TransformPhase `json:"transform,omitempty" yaml:"transform,omitempty" doc:"Value transformation phase"`
Validate *ValidatePhase `json:"validate,omitempty" yaml:"validate,omitempty" doc:"Value validation phase"`
// Messages contains user-defined messages shown on resolver outcomes.
Messages *Messages `json:"messages,omitempty" yaml:"messages,omitempty" doc:"Custom messages for resolver outcomes"`
}
Resolver represents a single resolver definition
func GetResolversInPhase ¶
func GetResolversInPhase(phases []*PhaseGroup, phaseNum int) []*Resolver
GetResolversInPhase returns all resolvers in a specific phase
type ResolverDiff ¶
type ResolverDiff struct {
Type DiffType `json:"type" yaml:"type" doc:"Type of difference (added, removed, modified, unchanged)" maxLength:"16" example:"modified"`
Before *SnapshotResolver `json:"before,omitempty" yaml:"before,omitempty" doc:"Value before change"`
After *SnapshotResolver `json:"after,omitempty" yaml:"after,omitempty" doc:"Value after change"`
Changes []FieldChange `json:"changes,omitempty" yaml:"changes,omitempty" doc:"List of field changes" maxItems:"50"`
}
ResolverDiff represents the difference for a single resolver
type ResolverLike ¶
ResolverLike is an interface for objects that have a Name and Sensitive flag nolint:revive // ResolverLike name is intentional to indicate compatibility with Resolver type
type ResolverMetric ¶
type ResolverMetric struct {
Name string `json:"name" yaml:"name" doc:"Resolver name" maxLength:"256" example:"api-data"`
Duration time.Duration `json:"duration,omitempty" yaml:"duration,omitempty" doc:"Execution duration"`
Size int64 `json:"size,omitempty" yaml:"size,omitempty" doc:"Value size in bytes" maximum:"1073741824" example:"1024"`
Phase int `json:"phase" yaml:"phase" doc:"Execution phase number" maximum:"100" example:"1"`
}
ResolverMetric contains metrics for a single resolver nolint:revive // ResolverMetric name is intentional for clarity in metrics context
type Snapshot ¶
type Snapshot struct {
Metadata SnapshotMetadata `json:"metadata" yaml:"metadata" doc:"Snapshot metadata"`
Parameters map[string]any `json:"parameters" yaml:"parameters" doc:"Parameters used in execution"`
Resolvers map[string]*SnapshotResolver `json:"resolvers" yaml:"resolvers" doc:"Resolver execution results"`
Phases []SnapshotPhase `json:"phases" yaml:"phases" doc:"Phase execution information" maxItems:"100"`
}
Snapshot represents a complete snapshot of resolver execution
func CaptureSnapshot ¶
func CaptureSnapshot( ctx context.Context, solutionName string, solutionVersion string, buildVersion string, parameters map[string]any, totalDuration time.Duration, overallStatus ExecutionStatus, ) (*Snapshot, error)
CaptureSnapshot creates a snapshot from execution context and results
func LoadSnapshot ¶
LoadSnapshot loads a snapshot from a JSON file
type SnapshotDiff ¶
type SnapshotDiff struct {
Before *SnapshotMetadata `json:"before" yaml:"before" doc:"Metadata of the before snapshot"`
After *SnapshotMetadata `json:"after" yaml:"after" doc:"Metadata of the after snapshot"`
Resolvers map[string]*ResolverDiff `json:"resolvers" yaml:"resolvers" doc:"Differences in resolvers"`
Summary *DiffSummary `json:"summary" yaml:"summary" doc:"Summary of changes"`
}
SnapshotDiff represents the differences between two snapshots
func DiffSnapshots ¶
func DiffSnapshots(before, after *Snapshot) *SnapshotDiff
DiffSnapshots compares two snapshots and returns their differences
func DiffSnapshotsWithOptions ¶
func DiffSnapshotsWithOptions(before, after *Snapshot, opts *DiffOptions) *SnapshotDiff
DiffSnapshotsWithOptions compares two snapshots with custom options
type SnapshotFailedAttempt ¶
type SnapshotFailedAttempt struct {
Provider string `json:"provider" yaml:"provider" doc:"Provider name" maxLength:"128" example:"http"`
SourceStep int `json:"sourceStep" yaml:"sourceStep" doc:"Source/step index in phase" maximum:"100" example:"0"`
Error string `json:"error" yaml:"error" doc:"Error message" maxLength:"4096" example:"timeout"`
Duration string `json:"duration" yaml:"duration" doc:"Time spent on this attempt" maxLength:"32" example:"5s"`
Timestamp string `json:"timestamp" yaml:"timestamp" doc:"When attempt occurred" maxLength:"64" example:"2026-01-29T12:00:00Z"`
}
SnapshotFailedAttempt contains information about a failed provider attempt
type SnapshotMetadata ¶
type SnapshotMetadata struct {
Solution string `json:"solution" yaml:"solution" doc:"Solution name" maxLength:"512" example:"my-solution"`
Version string `json:"version,omitempty" yaml:"version,omitempty" doc:"Solution version" maxLength:"64" example:"1.0.0"`
Timestamp time.Time `json:"timestamp" yaml:"timestamp" doc:"When snapshot was captured"`
Runtime SnapshotRuntime `json:"runtime" yaml:"runtime" doc:"Execution provenance (engine vs invoking CLI)"`
TotalDuration string `json:"totalDuration" yaml:"totalDuration" doc:"Total execution duration" maxLength:"32" example:"1.5s"`
Status string `json:"status" yaml:"status" doc:"Overall execution status (success, failed)" maxLength:"32" example:"success"`
}
SnapshotMetadata contains metadata about the snapshot
type SnapshotPhase ¶
type SnapshotPhase struct {
Phase int `json:"phase" yaml:"phase" doc:"Phase number (1-based)" maximum:"100" example:"1"`
Duration string `json:"duration" yaml:"duration" doc:"Phase execution duration" maxLength:"32" example:"500ms"`
Resolvers []string `json:"resolvers" yaml:"resolvers" doc:"Resolver names in this phase" maxItems:"500"`
}
SnapshotPhase contains information about a phase execution
type SnapshotResolver ¶
type SnapshotResolver struct {
Value any `json:"value" yaml:"value" doc:"Resolved value (or <redacted> if sensitive)"`
Status string `json:"status" yaml:"status" doc:"Execution status (success, failed, skipped)" maxLength:"32" example:"success"`
Phase int `json:"phase" yaml:"phase" doc:"Execution phase number" maximum:"100" example:"1"`
Duration string `json:"duration" yaml:"duration" doc:"Execution duration" maxLength:"32" example:"250ms"`
ProviderCalls int `json:"providerCalls" yaml:"providerCalls" doc:"Number of provider calls made" maximum:"1000" example:"3"`
ValueSizeBytes int64 `` /* 128-byte string literal not displayed */
Sensitive bool `json:"sensitive,omitempty" yaml:"sensitive,omitempty" doc:"Whether value was redacted"`
Error string `json:"error,omitempty" yaml:"error,omitempty" doc:"Error message if failed" maxLength:"4096" example:"connection refused"`
FailedAttempts []SnapshotFailedAttempt `` /* 129-byte string literal not displayed */
}
SnapshotResolver contains execution result for a single resolver
type SnapshotRuntime ¶ added in v0.34.0
type SnapshotRuntime struct {
Engine SnapshotRuntimeComponent `json:"engine" yaml:"engine" doc:"Execution engine (scafctl library) identity"`
CLI SnapshotRuntimeComponent `json:"cli" yaml:"cli" doc:"Invoking CLI/frontend identity"`
}
SnapshotRuntime records execution provenance, separating the engine (scafctl library) identity from the invoking CLI/frontend identity. When scafctl runs directly (not embedded), CLI mirrors Engine.
type SnapshotRuntimeComponent ¶ added in v0.34.0
type SnapshotRuntimeComponent struct {
Name string `json:"name" yaml:"name" doc:"Component name" maxLength:"64" example:"scafctl"`
Version string `json:"version" yaml:"version" doc:"Component version" maxLength:"64" example:"0.5.0"`
}
SnapshotRuntimeComponent identifies a named, versioned runtime participant.
type TemplateAccessor ¶ added in v0.33.0
type TemplateAccessor struct {
// Resolver is the name of the resolver containing the accessor.
Resolver string
// Step identifies where the accessor was found ("resolve" or "transform").
Step string
// Name is the unresolved accessor root name.
Name string
}
TemplateAccessor identifies a root-level Go template accessor in a resolver's resolve or transform step that does not resolve to any known resolver after accounting for data-input keys and forEach aliases. These are likely typos: at runtime a bare {{ .field }} accessor to an unknown root renders empty rather than failing, so they are surfaced as advisory findings rather than hard errors.
func UnresolvedTemplateAccessors ¶ added in v0.33.0
func UnresolvedTemplateAccessors(resolvers []*Resolver) []TemplateAccessor
UnresolvedTemplateAccessors scans the go-template "template" input of every resolve and transform step for root-level accessors that cannot resolve to any known resolver, data-input key, or forEach alias. A step whose data input has a dynamically-determined key set is skipped for bare {{ .field }} accessors (its root may be populated at runtime); {{ ._.name }} explicit resolver references are always checked. The returned accessors are likely typos and are intended to be surfaced as lint findings.
type TransformPhase ¶
type TransformPhase struct {
With []ProviderTransform `json:"with" yaml:"with" doc:"Ordered list of transformations" minItems:"1" maxItems:"200"`
When *Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Phase-level condition"`
}
TransformPhase defines how to derive a new value
type TypeCoercionError ¶
type TypeCoercionError struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Name of the resolver" example:"age-value"`
Phase string `json:"phase" yaml:"phase" doc:"Phase where coercion was attempted" enum:"resolve,transform" example:"resolve"`
SourceType string `json:"sourceType" yaml:"sourceType" doc:"Original type of the value" example:"string"`
TargetType Type `json:"targetType" yaml:"targetType" doc:"Target type for coercion" example:"int"`
Cause error `json:"-" yaml:"-" doc:"Underlying coercion error"`
CustomMessage string `json:"customMessage,omitempty" yaml:"customMessage,omitempty" doc:"User-defined error message from messages.error"`
}
TypeCoercionError represents a failure to coerce a value to the expected type.
func (*TypeCoercionError) Error ¶
func (e *TypeCoercionError) Error() string
Error implements the error interface.
func (*TypeCoercionError) Unwrap ¶
func (e *TypeCoercionError) Unwrap() error
Unwrap returns the underlying cause.
type ValidatePartition ¶ added in v0.34.0
type ValidatePartition struct {
// InlineRules holds indices into Validate.With for rules that stay inline.
InlineRules []int
// DeferredRules holds indices into Validate.With for rules that defer.
DeferredRules []int
// DeferredRefs is the union of foreign resolver references contributed by the
// deferred rules (and the phase-level when, when it forces deferral). These
// are used only to order and report deferred validation results; they are
// never resolution-graph edges.
DeferredRefs map[string]bool
// PhaseWhenDeferred indicates the phase-level validate.when referenced a
// foreign resolver, forcing the whole block to defer.
PhaseWhenDeferred bool
}
ValidatePartition classifies a resolver's validation rules into those that run inline (during resolution, preserving fail-fast) and those deferred to the post-resolution validation phase.
A rule is inline iff it references nothing but the owning resolver itself (self / __self). Any rule that references another resolver -- in its args, inputs, rule-level when, or message template -- is deferred and excluded from the resolution DAG. A phase-level validate.when that references a foreign resolver forces every rule in the block to defer (PhaseWhenDeferred).
func PartitionValidatePhase ¶ added in v0.34.0
func PartitionValidatePhase(r *Resolver, lookup DescriptorLookup) ValidatePartition
PartitionValidatePhase splits a resolver's validate phase into inline and deferred (cross-resolver) rule sets. It is the exported entry point used by tooling such as linters and embedders to reason about which validation rules run in the deferred phase. A nil resolver or nil validate phase yields an empty partition.
func (ValidatePartition) HasDeferred ¶ added in v0.34.0
func (p ValidatePartition) HasDeferred() bool
HasDeferred reports whether the partition contains any deferred rules.
type ValidatePhase ¶
type ValidatePhase struct {
With []ProviderValidation `json:"with" yaml:"with" doc:"Validation rules" minItems:"1" maxItems:"200"`
When *Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Phase-level condition"`
}
ValidatePhase defines validation constraints
type ValidationFailure ¶
type ValidationFailure struct {
Rule int `json:"rule" yaml:"rule" doc:"Rule number (0-indexed) that failed" minimum:"0" example:"0"`
Provider string `json:"provider" yaml:"provider" doc:"Validation provider name" example:"validation"`
Message string `` /* 129-byte string literal not displayed */
Cause error `json:"-" yaml:"-" doc:"Underlying error from the validation provider"`
Sensitive bool `json:"sensitive,omitempty" yaml:"sensitive,omitempty" doc:"Whether this failure contains sensitive information"`
}
ValidationFailure represents a single validation rule failure.
func (*ValidationFailure) Error ¶
func (f *ValidationFailure) Error() string
Error implements the error interface for a single failure.
type ValueRef ¶
ValueRef is an alias to spec.ValueRef for backward compatibility. It represents a value that can be literal, resolver reference, expression, or template.
type ValueSizeError ¶
type ValueSizeError struct {
ResolverName string `json:"resolverName" yaml:"resolverName" doc:"Name of the resolver with oversized value" example:"large-data"`
ActualSize int64 `json:"actualSize" yaml:"actualSize" doc:"Actual size of the value in bytes" minimum:"0" example:"10485760"`
MaxSize int64 `json:"maxSize" yaml:"maxSize" doc:"Maximum allowed size in bytes" minimum:"1" example:"1048576"`
}
ValueSizeError represents a value that exceeds the maximum allowed size.
func (*ValueSizeError) Error ¶
func (e *ValueSizeError) Error() string
Error implements the error interface.