Change record status: 
Project: 
Introduced in branch: 
2.x
Introduced in version: 
2.3.0
Description: 

Problem/Motivation

GraphState::withOutcomeCleared() is used by StateGraph thread continuity: when a
session starts a new turn, the thread's latest checkpoint seeds the new run so the
conversation carries over. The method cleared the previous run's outcome
(isComplete, error, status) but kept its execution position, and the loop
iterator was explicitly classified as accumulated state.

That classification was wrong. A ForEach that runs to completion leaves an
exhausted iterator (final index, hasMore FALSE). Seeding the next turn with it
made that turn's loop emit a null item and fall straight through without iterating —
and because the non-iterating turn then wrote a fresh iterator back, turns
alternated between working and not. A loop printing 1, 2, 3 on one run printed
nothing on the next.

iterationCount carried the same defect one step further out: it feeds the
maxIterations budget in StateManager, so carrying it across turns spent a thread's
entire loop budget on whichever run exhausted it first.

Changes

The seed now splits on scope rather than on outcome:

Scope Fields Behaviour
Thread-scoped messages, data, metadata, threadId carried into the new turn
Run-scoped isComplete, error, status, iterator, iterationCount, currentNodeId cleared

withOutcomeCleared() no longer describes what the method does, so it is deprecated
in favour of withRunStateCleared().

Only the terminal arm clears. A paused or interrupted run restores through the
non-terminal arm untouched, so a mid-loop pause still resumes at its exact position.

Before

  $seed = $restored->withOutcomeCleared();
  // Kept the finished run's iterator and iterationCount.</p>

After

  $seed = $restored->withRunStateCleared();
  // Clears the finished run's outcome AND its execution position.

withOutcomeCleared() keeps working until FlowDrop 3.0.0, but it delegates to
withRunStateCleared() and therefore carries the corrected behaviour. There is no
way to opt back into the old behaviour: a caller who wanted the outcome dropped while
the execution position was kept was relying on the defect.

No runtime deprecation notice is triggered. The one production caller is the
thread-continuity seed, which runs once per turn; the BC policy asks for documented
rather than triggered deprecations on paths that would flood a site's log.

Impact

  • Sites with a loop inside a chat/session workflow are affected and fixed: loops
    now run on every turn instead of every other one.
  • Code calling withOutcomeCleared() directly keeps working with no change
    required before 3.0.0, but receives the corrected behaviour immediately.
  • Spec rules SG-12 and INT-13.
Impacts: 
Module developers