Skip to content

RFC(runtime): model Goal continuation as a durable consumer loop #3194

Description

@likun666661

Problem

Goal continuation is conceptually a durable consumer loop:

  1. consume one durable terminal Turn;
  2. evaluate whether the Goal should stop;
  3. if it should continue, atomically enqueue exactly one successor Execution.

The current implementation preserves this behavior through several overlapping pieces of authority:

  • Goal revision checkpoints;
  • control-lease generations;
  • Goal-authority revisions;
  • an in-memory continuation intent and per-Session FIFO lane;
  • a durable currentExecution pointer;
  • busy wakeups, waiting timers, and recovery reconciliation.

Each mechanism addresses a real race. Taken together, however, they suggest that one missing concept is being reconstructed indirectly: a durable Goal loop iteration, or Goal Step.

The central correctness problem is the classic dual-write boundary:

commit the consumed Goal result
+
enqueue the successor Execution

If the state commit wins and enqueue is lost, an active Goal becomes a zombie. If enqueue wins and the state commit is lost, recovery can create a duplicate successor. The current coordinator closes these windows in application code, but correctness is spread across transient scheduler state and multiple clocks.

This increases the number of states and recovery branches that maintainers must reason about, especially across pause/resume, concurrent Turns, Session retirement, Host drain, and restart.

Desired outcome

Model Goal as a durable consumer loop whose iteration is first-class in storage.

A minimal authoritative Goal record could be:

goal_id
session_id
condition
status        # running | paused | terminal
version       # optimistic concurrency + fencing token
cursor        # last durably settled Turn/Step
policy        # optional limits

The existing Execution admission ledger could carry the Step identity:

goal_id
goal_version
step_number
execution_id
status
not_before    # optional waiting policy

with durable uniqueness such as:

UNIQUE(goal_id, step_number)
UNIQUE(execution_id)

The authoritative transition would be one storage transaction:

CAS Goal(version)
advance Goal.cursor / status
if continuing:
    insert exactly one pending successor Execution
commit

This gives the pending Execution the meaning currently split between continuation intent and currentExecution.

The intended invariants are:

  1. A Goal cursor advances monotonically.
  2. A settled Step has at most one successor.
  3. A worker may execute a Step only when its Goal version still matches.
  4. A running Goal has either durable terminal evidence ready to consume or one durable pending/admitted/running successor.
  5. Provider dispatch recovery remains entirely owned by the existing Execution/Resume layer, including outcome_unknown.

Under this model:

  • goal_id + version is the ordinary CAS/fencing identity;
  • a pending Execution is the durable continuation intent;
  • the current Execution is derived from the Execution ledger rather than maintained as independent authority;
  • database ordering and uniqueness provide correctness, while an in-memory lane may remain only as an optimization;
  • waiting is a scheduled pending Step with not_before, rather than a separate continuation control path;
  • counters such as iteration count, token spend, progress streak, and last reason may be derived or explicitly materialized as policy caches.

Suggested migration

  1. Document the Goal loop invariants independently of the current coordinator.
  2. Introduce a stable Goal Step identity on Goal-owned root-turn admissions.
  3. Add uniqueness and fencing constraints for successor creation and worker claim.
  4. Add a storage transaction that settles one consumed Step and inserts its successor.
  5. Route startup recovery through pending/admitted Execution state.
  6. After fault-injection parity is established, remove authority that has become derived or redundant.

The migration should be validated with crash injection at every boundary:

  • before and after Goal settlement commit;
  • before and after successor insertion;
  • before and after Execution admission;
  • after provider dispatch with unknown outcome;
  • during pause/resume and Session retirement.

The required proof is that restart produces neither a lost continuation nor more than one successor for the same Step.

Alternatives or workarounds

The current coordinator can remain as-is and continue to encode the protocol through checkpoint, controlLease, retained intent, currentExecution, and reconciliation. That is behaviorally valid, but it leaves the durable loop protocol distributed across runtime, Runtime Host, and storage.

If Goal settlement and successor admission cannot share a physical transaction, an explicit transactional-outbox row is the next-smallest model. It should still be the sole durable continuation intent, with Execution admission consuming it idempotently.

This proposal does not change evaluator policy, budgets, Task Ledger integration, or provider Resume semantics. It only aims to reduce the correctness model to a durable cursor, one fencing version, and one uniquely identified successor Step.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions