func (s *Service) applyGuardedTransitionLifecycle(ctx context.Context, taskID, sessionID, fromStepID, toStepID string, trigger engine.Trigger) (bool, error)
Introduces a guarded-decision lifecycle mode that moves the task step but skips session on_exit and on_enter continuation, so the reviewer session is not prompted into Work.
Lifecycle modes
// transitionLifecycleMode identifies the caller-owned part of a transition.
// Guarded decisions use a session-independent mode because the session passed
// by the engine is the decider's session, not the assignee's destination
// session.
type transitionLifecycleMode uint8
const (
transitionLifecycleWithOnEnter transitionLifecycleMode = iota
transitionLifecycleOnTurnStart
transitionLifecycleGuardedDecision
)
applyGuardedTransitionLifecycle
func (s *Service) applyGuardedTransitionLifecycle(
ctx context.Context, taskID, sessionID, fromStepID, toStepID string, trigger engine.Trigger,
) (bool, error) {
if s.workflowStore == nil {
return false, errors.New("workflow store is not initialized")
}
task, err := s.repo.GetTask(ctx, taskID)
if err != nil {
return false, fmt.Errorf("load task for guarded transition lifecycle: %w", err)
}
session, err := s.repo.GetTaskSession(ctx, sessionID)
if err != nil {
return false, fmt.Errorf("load session for guarded transition lifecycle: %w", err)
}
casAttempted := false
casApplied := false
lifecycleApplied := s.applyEngineTransitionWithCommitMode(
ctx,
taskID,
session,
engine.HandleResult{Transitioned: true, FromStepID: fromStepID, ToStepID: toStepID},
trigger,
task.Description,
transitionLifecycleGuardedDecision,
func(commitCtx context.Context) (bool, error) {
casAttempted = true
transitionCtx := commitCtx
if !steptelemetry.HasTrigger(transitionCtx) {
transitionCtx = engineTransitionAttribution(transitionCtx, sessionID, trigger)
}
committedTask, oldWorkflowID, applied, commitErr := s.workflowStore.applyTransitionIfAtStepRaw(
transitionCtx, taskID, fromStepID, toStepID,
)
if commitErr != nil {
return false, commitErr
}
if !applied {
return false, nil
}
casApplied = true
s.publishTaskUpdated(ctx, committedTask, oldWorkflowID)
s.workflowStore.pullNextTaskOnVacate(ctx, fromStepID, taskID)
return true, nil
},
)
if lifecycleApplied || casApplied {
return true, nil
}
if casAttempted {
return false, nil
}
return false, errors.New("guarded transition lifecycle did not apply")
}
Session lifecycle gate
func (s *Service) applyEngineTransitionWithCommitMode(
ctx context.Context, taskID string, session *models.TaskSession,
result engine.HandleResult, trigger engine.Trigger, taskDescription string,
mode transitionLifecycleMode, commit func(context.Context) (bool, error),
) bool {
ctx = withWorkflowMetaCache(ctx)
sessionLifecycle := mode != transitionLifecycleGuardedDecision
// ...
if sessionLifecycle {
s.processOnExit(ctx, taskID, session, fromStep)
}
// ...
if mode == transitionLifecycleGuardedDecision {
return true
}
if mode == transitionLifecycleOnTurnStart {
effectiveSession, ok := s.maybySwitchSessionForProfile(ctx, taskID, session, targetStep, fromStep)
if !ok {
return false
}
s.setSessionWaitingForInput(ctx, taskID, effectiveSession.ID)
return true
}
}