diff --git a/CONTEXT.md b/CONTEXT.md index cc9ad755..140e5bc5 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -260,6 +260,27 @@ state, records trace, and persists runs predictably even when individual capabilities call nondeterministic tools, APIs, Python code, or LLMs. _Avoid_: Deterministic external tools, deterministic LLM output +**Runtime Scope**: +The state universe for one workflow invocation, containing its input and +committed state. Every state lineage belongs to exactly one runtime scope. +_Avoid_: Execution frame, branch, global run state + +**State Lineage**: +One isolated state worldview inside a runtime scope. Its ancestry describes +state visibility, independently of which execution frame currently uses it. +_Avoid_: Execution frame, scheduler task, activation token + +**Execution Frame**: +A schedulable graph cursor that executes against one state lineage. Frame +ancestry describes scheduling ownership and block/wake behavior, not state +ancestry. +_Avoid_: State lineage, workflow invocation, operating-system thread + +**Frame Completion**: +The end of one execution frame. Its owner determines whether this completes a +workflow invocation, returns from a subgraph, or completes one foreach item. +_Avoid_: Always completing the run, domain outcome, implicit break + **Fork**: An explicit workflow control step that creates several concurrent branch activations. A fork is distinct from an ordinary outcome, which selects exactly @@ -275,10 +296,10 @@ _Avoid_: Pass-through join marker, arbitrary graph convergence, reference to one originating fork **Activation Token**: -A runtime value identifying one control-flow arrival, its workflow scope, -lineage worldview, activation context, and merge provenance. Compatible tokens -can rendezvous at a gather without mixing loop iterations, subgraph -invocations, or repeated fork activations. +A runtime value identifying one control-flow arrival, its state lineage, +activation context, and merge provenance. Compatible tokens can rendezvous at +a gather without mixing loop iterations, subgraph invocations, or repeated +fork activations. The lineage determines the token's runtime scope. _Avoid_: Static edge, node output payload, scheduler position **Gather Slot**: @@ -534,14 +555,6 @@ _Avoid_: Global committed state A merge boundary that waits for multiple child or upstream frames and combines their lineage patches before continuation. _Avoid_: Noop join -**Gather Node**: -A future graph step that exposes an explicit barrier for waiting on multiple branches and merging their results. -_Avoid_: Promise.all node, converge node - -**Lineage Token**: -A future runtime marker for one branch lineage that can be consumed and merged by gather-style barriers. -_Avoid_: Edge id - **Run**: One execution attempt of a workflow with input, state, frames, trace, and final output. _Avoid_: Job, invocation @@ -549,6 +562,11 @@ _Avoid_: Job, invocation ## Relationships - A **Run** owns one or more **Frames**. +- Every **State Lineage** belongs to exactly one **Runtime Scope**. +- Every **Execution Frame** executes against one **State Lineage** and derives + its runtime scope through that lineage. +- Frame ancestry expresses scheduling ownership; lineage ancestry expresses + state visibility. - A **Frame Set** is the source of truth for runtime cursors. - The **Scheduler Foundation** selects one **Runnable Frame** at a time in the first pass. diff --git a/docs/adr/0006-explicit-fork-and-topology-driven-gather.md b/docs/adr/0006-explicit-fork-and-topology-driven-gather.md index 2e6a55ee..0070f373 100644 --- a/docs/adr/0006-explicit-fork-and-topology-driven-gather.md +++ b/docs/adr/0006-explicit-fork-and-topology-driven-gather.md @@ -59,6 +59,21 @@ one token per slot for an activation, waits until all slots are present, then merges their lineage-local patches. Its result is a new continuation token that preserves combined provenance and can enter another gather. +Runtime identity follows one canonical dependency chain. A runtime scope is one +workflow invocation and its committed state universe. A lineage belongs to +exactly one scope and represents one isolated state worldview inside it. An +execution frame is a schedulable graph cursor that executes against one +lineage, so the frame's scope and parent lineage are derived through that +lineage rather than independently stored relationships. Frame ancestry remains +separate: a parent frame expresses scheduling ownership and block/wake behavior, +not state ancestry. + +Lineages are not owned by frames. A completed branch frame may leave its +lineage waiting at a gather, and a later continuation frame may execute against +the lineage produced by a merge. Activation tokens bind a control-flow arrival +to its lineage plus the correlation and provenance needed by gathers; they do +not duplicate the lineage's scope membership. + Lineage remains a virtual worldview: committed scope state plus writes visible to one branch. Gathering several lineages does not require turning lineage ancestry into a multi-parent graph. A partial gather can create an intermediate @@ -82,6 +97,21 @@ overlap in the asynchronous runtime. Both modes must produce equivalent graph semantics. Scheduler order decides when compatible work progresses, never which arrivals belong together. +`END` means completion of the current execution frame, not necessarily +completion of the whole run. The frame owner determines the consequence: a +root frame completes its workflow invocation, a subgraph root returns to its +parent boundary, and a foreach item reports completion to its parent barrier. +For a foreach, normal item-frame completion therefore allows the controller to +admit or resume the next item without introducing a separate continue node. + +General break and race behavior are not part of the first fork/gather design. +The existing foreach `fail`, `skip`, and `collect` policies describe the +disposition of runtime item failures; they are distinct from completion +policies such as first-completed, first-error, or all-completed. A future break +feature would require an operational signal to the owning foreach and an +explicit policy for already admitted concurrent items. No `BreakNode` is added +without that use case and policy. + The current `JoinNode` will not be silently upgraded. Before implementation we will verify whether real persisted artifacts use it. With no real compatibility obligation, remove it and introduce `GatherNode` cleanly. If persisted callers @@ -106,6 +136,16 @@ AND across slots and OR within a slot. belongs to activation tokens; an intermediate merged worldview can remain a child of the compatible inputs' common lineage parent. +**Store scope and parent-lineage identity on every frame.** Rejected because +those relationships are canonical on the lineage and duplicated frame fields +can disagree with them. Runtime operations should resolve and validate a +frame's lineage and scope together. + +**Model normal foreach completion as a continue node.** Rejected because +completion of an item frame already returns control to the owning foreach. +Break and race semantics remain separate future policies rather than additional +meanings assigned to ordinary outcomes. + **Reuse or rename `JoinNode`.** Rejected as the default because the existing node is a pass-through marker with no barrier contract. @@ -118,6 +158,12 @@ node is a pass-through marker with no barrier contract. `(node, outcome)` pair. - Checkpoints must persist pending gather arrivals and activation provenance so interruption/resume cannot mix loop iterations or subgraph invocations. +- Runtime operations should resolve a frame, its lineage, and its scope through + one internal interface instead of accepting several independently supplied + identifiers. +- Persisted frame state should not duplicate scope or parent-lineage + relationships once real checkpoint compatibility has been checked and any + required migration has been defined. - Trace output must make fork activation, branch identity, gather waiting, and merged continuation inspectable without treating scheduler bookkeeping as ordinary node output. @@ -129,8 +175,8 @@ node is a pass-through marker with no barrier contract. ## Open Questions - The exact serialized edge field and authoring name for a gather slot. -- The minimal activation-context and provenance representation that supports - loops, nested forks, subgraphs, partial gathers, and cross-merges. +- The minimal activation-correlation and provenance representation that + supports loops, nested forks, subgraphs, partial gathers, and cross-merges. - Whether a gather resumes an existing blocked frame or creates a dedicated continuation frame in each topology shape. - The trace representation for waiting and merging without excessive internal