Reason codes
Stable typed identifiers for every decision outcome — what you build dashboards, alarms, and tests on.
Vadyl emits stable typed reason codes for every meaningful decision: access granted or denied, cache hit or miss, plan choice, deployment outcome, scheduled run outcome, agent step. Reason codes are the canonical handles you build dashboards, alarms, tests, and remediation flows on — not parsed log strings.
Why reason codes
- Stable across releases — code names don't shift; you can rely on switch statements over them.
- Localized at render — the dashboard maps codes to user-facing messages per locale.
- Test-asserted — tests can pin behavior on reason codes without coupling to message text.
- Cross-surface — REST, GraphQL, gRPC, SDK, CLI all emit the same codes for the same decisions.
Reason code blocks
Codes are organized into typed blocks. Each block lives next to the plane that emits it:
AccessReasonCodes
Access.AllowedByOwnerRule
Access.AllowedByRoleMembership
Access.AllowedByContextSet
Access.AllowedBypass
Access.DeniedByMissingClaim
Access.DeniedByContextSetMismatch
Access.DeniedByExplicitDeny
Access.DeniedByAuthStrengthBelowMinimum
Access.MaskedByFieldRuleReadPlanReasonCodes
ReadPlan.SatisfiedByCache
ReadPlan.RoutedToReadReplica
ReadPlan.NativeProviderExecution
ReadPlan.RuntimeSupplemented
ReadPlan.CrossProviderJoin
ReadPlan.PaginationApplied
ReadPlan.SortAppliedAtProvider
ReadPlan.SortAppliedAtRuntimeSurfaceReasonCodes
Surface.RouteResolved
Surface.OperationDispatched
Surface.SerializationFormatNegotiated
Surface.RateLimited
Surface.NotFoundByPath
Surface.MethodNotAllowedProjectRuntimeReasonCodes
ProjectRuntime.PublicationCompiled
ProjectRuntime.PublicationFrozenByMaintenance
ProjectRuntime.BindingResolved
ProjectRuntime.BindingDroppedByGovernanceEnvelope
ProjectRuntime.GovernanceEnvelopeUnavailableAuthoredPublicationReasonCodes
AuthoredPublication.ArtifactBound
AuthoredPublication.ArtifactSignatureVerified
AuthoredPublication.ArtifactRejectedSignatureMismatch
AuthoredPublication.LatestSelected
AuthoredPublication.PinnedSelectedAgentReasonCodes
Agent.PlanValidated
Agent.PlanRejectedRiskBudget
Agent.PlanRejectedQuotaProjection
Agent.StepDispatched
Agent.StepFailedRetried
Agent.StepFailedTerminal
Agent.MemoryRecallSucceeded
Agent.MemoryRecallEmptySchemaTransitionReasonCodes
SchemaTransition.ClassifiedMetadataOnly
SchemaTransition.ClassifiedInstant
SchemaTransition.ClassifiedNativeOnline
SchemaTransition.ClassifiedExpandThenBackfill
SchemaTransition.ClassifiedBlocking
SchemaTransition.ClassifiedDestructiveUse them
From the SDK:
try {
await sdk.orders.update(id, { status: "refunded" });
} catch (err) {
if (err.reasonCode === "Access.DeniedByContextSetMismatch") {
// surface a precise UI hint
}
}From observability:
vadyl audit tail --filter "reasonCode startsWith 'Access.Denied'"
vadyl explain access --entity Order --filter "id=abc" \
| jq '.decision.reasonCode'Adding a new reason code
New codes are added to the appropriate block. They never get deleted (only deprecated and replaced) — consumers depend on them across releases. Deprecation comes with a 12-month minimum window and clear documentation pointing at the replacement code.