Editorial Workflows

Evaluation insights

Explain condition outcomes and field proposals from an Editorial Workflows evaluation.

Prerelease

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

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.

Use insights to answer two questions in a custom interface or diagnostic: why is this action, requirement, transition, or field in its current state; and which condition outcomes would change if a field were set to 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:

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 be involved in several conditions without having a useful proposal. Proposals appear only when a blocking atom identifies one concrete value and re-evaluation confirms that the assignment changes at least one involved site.

  • 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 independently. The package’s TypeScript declarations provide the exhaustive parameter documentation.

Next steps

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

Use App SDK for a practical example that renders blocked transition atoms.

See Engine for the complete WorkflowEvaluation projection.

Visiting agent?

Was this page helpful?