Workflows

Evaluation insights

Explain condition outcomes and field proposals from a Workflows evaluation.

Early access

Workflows evaluates a running workflow instance to answer what the current actor can see and do now. The result is a WorkflowEvaluation: a read-only projection of the current stage, activities, transitions, editable fields, and action verdicts.

A direct engine integration receives this projection from engine.evaluate({instanceId}). A custom App SDK interface receives the same projection as session.evaluation from the reactive session. The session recomputes it when the workflow instance, referenced content, guards, or field previews change.

Authored semantics appear unchanged on WorkflowEvaluation.semantics, currentStage.semantics, and each activity and action evaluation. They are advisory metadata, separate from verdicts and condition insights.

Insights are explanations nested inside an evaluation. A condition insight explains why one condition is satisfied, unsatisfied, or unevaluable. WorkflowEvaluation.fieldInsights groups those explanations by the fields that the conditions read.

Insights answer two questions in a custom interface or diagnostic. Why is this action, requirement, transition, or field in the state it is in? And which condition outcomes would change if a field held a proposed value? You do not need insights to write conditions.

Insights describe the engine’s current advisory evaluation. They do not enforce access or replace Content Lake permissions.

Explain a waiting transition

Suppose a custom workflow screen must explain why its publish transition is waiting and what field changes would affect that decision. Pass the current WorkflowEvaluation to a helper that reads both the transition insight and the field proposals:

import type {ConditionOutcome, WorkflowEvaluation} from '@sanity/workflow-engine'

interface TransitionChange {
  field: string
  value: unknown
  before: ConditionOutcome
  after: ConditionOutcome
}

interface TransitionExplanation {
  outcome: ConditionOutcome
  blockedBy: string[]
  changes: TransitionChange[]
}

export function explainTransition(
  evaluation: WorkflowEvaluation,
  transitionName: string,
): TransitionExplanation {
  const evaluated = evaluation.currentStage.transitions.find(
    ({transition}) => transition.name === transitionName,
  )

  if (!evaluated) throw new Error(`Unknown transition: ${transitionName}`)

  const changes = evaluation.fieldInsights.flatMap((field) =>
    field.proposals.flatMap((proposal) =>
      proposal.consequences
        .filter(
          ({site}) => site.kind === 'transition' && site.transition === transitionName,
        )
        .map(({before, after}) => ({
          field: field.field,
          value: proposal.assign.value,
          before,
          after,
        })),
    ),
  )

  return {
    outcome: evaluated.insight.outcome,
    blockedBy: evaluated.insight.blockedBy.map(({atom}) => atom.groq),
    changes,
  }
}

Call explainTransition(session.evaluation, 'to-publishing'). The returned blockedBy list explains why the transition is waiting. Each changes entry names a proposed field value and the transition outcome before and after that value. These are verified condition consequences, not a prediction of document writes or external effects.

The outcome has three possible values:

  • satisfied: the condition is true.
  • unsatisfied: the condition is false.
  • unevaluable: GROQ returned null because the condition could not be decided from the current values.

Where condition insights appear

Evaluated nodes expose the insight beside the decision it explains:

Explain missing referenced content

A workflow can be unable to advance because a selected document cannot be read. This includes a required content reference, or an optional reference needed by an unmet runtime requirement or transition condition. See Fields for requiredness and repair.

WorkflowEvaluation.missingDocuments identifies absent targets in active field scopes. Each MissingDocument carries the field target, document reference, and declared title when available. blockingMissingDocuments selects those that prevent current progress. Use it when explaining a blocked workflow; absence alone does not make every action unavailable.

When present, each entry's availability field carries the result of a completed check:

  • deleted

    DocumentAvailability

    The availability check confirms absence across published, draft, and release representations.

  • unreadable

    DocumentAvailability

    Access is denied, or the availability check failed or is unsupported. Do not describe this result as deletion.

  • outside-perspective

    DocumentAvailability

    A representation exists, but it is absent from the content snapshot evaluated for this workflow.

An evaluation built from a supplied snapshot can omit availability. Treat that as missing evidence. evaluateFromSnapshot accepts a documentAvailability reader when your integration can provide the completed check.

Use the action's complete verdict when enabling a control. Required-reference checks appear in unmetRequirements under field:<name>, without entries in requirementInsights. A satisfied transition condition also does not override a missing required reference.

Read field insights

WorkflowEvaluation.fieldInsights provides the field-centric view of the same current-stage conditions. Use it to show where a field matters and which concrete assignments the engine verified would change an outcome.

A field can take part in several conditions without producing a useful proposal. A proposal appears only when a blocking atom points to one concrete value, and re-evaluating with that value confirms it changes at least one of the sites involved.

  • field

    string

    The rendered $fields entry name.

  • reads

    ConditionRead[]

    Every distinct read of that field across current-stage condition sites.

  • involvedIn

    InsightSite[]

    The actions, action triggers, activity filters, requirements, transitions, or editable fields whose conditions read it.

  • proposals

    FieldProposal[]

    Verified assignments and the condition sites whose outcomes they change. Empty when no single concrete assignment can be proposed.

Condition insight reference

  • analysis

    ConditionAnalysis

    The parsed condition, its atom tree, and the scope reads found in it.

  • outcome

    'satisfied' | 'unsatisfied' | 'unevaluable'

    The engine’s verdict for the complete condition.

  • atoms

    AtomInsight[]

    Every atomic predicate with its outcome, pivotal flag, and any derivable requirement.

  • frontier

    ConditionClause | undefined

    The remaining unmet clause tree. Absent when the condition is satisfied.

  • blockedBy

    AtomInsight[]

    A flat, source-ordered list of the unmet frontier. Empty when the condition is satisfied.

AtomInsight

  • atom

    ConditionAtom

    The atomic predicate. Use atom.groq for display.

  • outcome

    ConditionOutcome

    The atom’s current verdict.

  • pivotal

    boolean

    True when satisfying this atom alone, while other atoms keep their current outcomes, would satisfy the condition.

  • requirement

    AtomRequirement | undefined

    A machine-readable requirement when the atom can be solved from one scope read and a literal value.

Exports and utilities

The insight types and utilities shown on this page are exported from @sanity/workflow-engine. Import only the shapes and functions your integration uses:

import type {
  AtomInsight,
  AtomRequirement,
  ConditionInsight,
  ConditionOutcome,
  ConditionRead,
  FieldInsight,
  FieldProposal,
  InsightSite,
  ScopeAssignment,
  SiteConsequence,
} from '@sanity/workflow-engine'

import {
  analyzeCondition,
  explainCondition,
  whatIfCondition,
} from '@sanity/workflow-engine'

Engine and reactive consumers usually read the insights already present on WorkflowEvaluation. Use these utilities only when you need to analyze or evaluate a condition on its own. The package’s TypeScript declarations document every parameter.

Next steps

Use The reactive session to keep the evaluation current in a custom interface.

See Build a workflow interface with the App SDK for a practical example that renders blocked transition atoms.

See Engine for the complete WorkflowEvaluation projection.

Visiting agent?

Was this page helpful?