Reference

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.MaskedByFieldRule

ReadPlanReasonCodes

ReadPlan.SatisfiedByCache
ReadPlan.RoutedToReadReplica
ReadPlan.NativeProviderExecution
ReadPlan.RuntimeSupplemented
ReadPlan.CrossProviderJoin
ReadPlan.PaginationApplied
ReadPlan.SortAppliedAtProvider
ReadPlan.SortAppliedAtRuntime

SurfaceReasonCodes

Surface.RouteResolved
Surface.OperationDispatched
Surface.SerializationFormatNegotiated
Surface.RateLimited
Surface.NotFoundByPath
Surface.MethodNotAllowed

ProjectRuntimeReasonCodes

ProjectRuntime.PublicationCompiled
ProjectRuntime.PublicationFrozenByMaintenance
ProjectRuntime.BindingResolved
ProjectRuntime.BindingDroppedByGovernanceEnvelope
ProjectRuntime.GovernanceEnvelopeUnavailable

AuthoredPublicationReasonCodes

AuthoredPublication.ArtifactBound
AuthoredPublication.ArtifactSignatureVerified
AuthoredPublication.ArtifactRejectedSignatureMismatch
AuthoredPublication.LatestSelected
AuthoredPublication.PinnedSelected

AgentReasonCodes

Agent.PlanValidated
Agent.PlanRejectedRiskBudget
Agent.PlanRejectedQuotaProjection
Agent.StepDispatched
Agent.StepFailedRetried
Agent.StepFailedTerminal
Agent.MemoryRecallSucceeded
Agent.MemoryRecallEmpty

SchemaTransitionReasonCodes

SchemaTransition.ClassifiedMetadataOnly
SchemaTransition.ClassifiedInstant
SchemaTransition.ClassifiedNativeOnline
SchemaTransition.ClassifiedExpandThenBackfill
SchemaTransition.ClassifiedBlocking
SchemaTransition.ClassifiedDestructive

Use 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.