refactor: remove placeholder join step
This commit is contained in:
@@ -14,9 +14,10 @@ without making multiple matching edges silently mean broadcast.
|
||||
|
||||
The scheduler, ready queue, blocked frames, lineage-local state views, and
|
||||
reducer-aware barrier commits already support concurrent foreach and native
|
||||
subgraphs. They do not yet define general graph-level fork/gather. The existing
|
||||
`JoinNode` is only a day-one marker: it immediately emits `done` and neither
|
||||
waits nor merges. Renaming it would falsely preserve semantics it never had.
|
||||
subgraphs. They do not yet define general graph-level fork/gather. A former
|
||||
`JoinNode` day-one marker immediately emitted `done`; it was removed after a
|
||||
census found no real persisted workflows using it. `GatherNode` therefore does
|
||||
not inherit placeholder semantics or a compatibility burden.
|
||||
|
||||
A cross-system semantics review supported keeping `NodeResult.output` separate
|
||||
from its named domain `outcome`, keeping operational failure outside that
|
||||
@@ -135,11 +136,10 @@ 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
|
||||
exist, define an explicit migration rather than assigning barrier semantics to
|
||||
old `join` payloads.
|
||||
The placeholder `JoinNode` was removed rather than silently upgraded. The
|
||||
repository has no real persisted artifacts outside tests, so `GatherNode` can
|
||||
be introduced with its actual rendezvous and merge contract and no legacy wire
|
||||
alias.
|
||||
|
||||
## Considered Options
|
||||
|
||||
@@ -169,8 +169,8 @@ ordinary back-edge to the owning foreach already expresses item return in the
|
||||
canonical graph. 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.
|
||||
**Reuse or rename the placeholder `JoinNode`.** Rejected and removed because
|
||||
the node was a pass-through marker with no barrier contract.
|
||||
|
||||
## Consequences
|
||||
|
||||
@@ -206,7 +206,6 @@ node is a pass-through marker with no barrier contract.
|
||||
continuation frame in each topology shape.
|
||||
- The trace representation for waiting and merging without excessive internal
|
||||
scheduler noise.
|
||||
- Whether any real persisted artifact requires migration from `JoinNode`.
|
||||
|
||||
This ADR extends the lineage and barrier direction established by
|
||||
[ADR-0002](0002-concurrent-foreach-policy-and-barrier-commits.md). It remains
|
||||
|
||||
+17
-15
@@ -40,23 +40,12 @@ author -> validate -> save artifact -> deploy -> run -> inspect or resume
|
||||
|
||||
## Active runtime sequence
|
||||
|
||||
The next three slices build on the foreach control-region, scheduler, lineage,
|
||||
and barrier foundations in this order.
|
||||
The next three slices build on the foreach control-region, structured-context,
|
||||
scheduler, lineage, and barrier foundations in this order.
|
||||
|
||||
### 1. Review and merge structured runtime context
|
||||
### 1. Add a persisted run step budget
|
||||
|
||||
The implementation plan is ready and its feature branch is under review:
|
||||
|
||||
- [`structured runtime context design`](superpowers/specs/2026-09-04-structured-runtime-context-design.md)
|
||||
- [`structured runtime context implementation plan`](historical/superpowers/plans/2026-09-04-structured-runtime-context.md)
|
||||
|
||||
This slice gives runtime code, expressions, validation, and authoring references
|
||||
one model for run data and same-scope foreach activations. Subgraphs continue to
|
||||
cross an explicit input boundary rather than inheriting a parent's context.
|
||||
|
||||
### 2. Add a persisted run step budget
|
||||
|
||||
After structured context is stable, implement the proposed run-wide limit:
|
||||
Implement the proposed run-wide limit:
|
||||
|
||||
- [`run step budget design`](superpowers/specs/2026-09-04-run-step-budget-design.md)
|
||||
|
||||
@@ -64,6 +53,13 @@ The budget must cover every frame and subgraph scope in one run, survive
|
||||
checkpoint and resume, and stop valid but non-terminating graph cycles with a
|
||||
clear runtime failure.
|
||||
|
||||
### 2. Consolidate runtime identity resolution
|
||||
|
||||
Introduce one internal resolver for a frame, lineage, runtime scope, and
|
||||
foreach activation environment. The resolver should validate the canonical
|
||||
identity chain once so fork/gather code does not pass related identifiers
|
||||
independently or repeat ownership walks.
|
||||
|
||||
### 3. Implement explicit fork and gather
|
||||
|
||||
Reuse the scheduler, activation, lineage, and reducer-aware barrier machinery:
|
||||
@@ -140,12 +136,18 @@ The active sequence can assume these foundations:
|
||||
- Native subgraph scopes and durable return to the parent node
|
||||
- Concurrent foreach with activation barriers and reducer-aware lineage merges
|
||||
- Validated foreach back-edges with one static control region per node use
|
||||
- Structured runtime context shared by execution, expressions, validation, and
|
||||
authoring references
|
||||
- Removal of the pass-through `JoinNode`; future `GatherNode` starts with its
|
||||
actual synchronization contract and no placeholder compatibility
|
||||
- Durable stopped-run inspection and resume
|
||||
- Python client reconstruction of capabilities, artifacts, deployments, and
|
||||
runs through the API
|
||||
|
||||
The current foreach return contract is
|
||||
[`foreach back-edge design`](superpowers/specs/2026-09-04-foreach-back-edge-design.md).
|
||||
The current context contract is
|
||||
[`structured runtime context`](superpowers/specs/2026-09-04-structured-runtime-context-design.md).
|
||||
|
||||
## Historical entry points
|
||||
|
||||
|
||||
@@ -112,7 +112,6 @@ Exactly one step-kind key must be present. Allowed step-kind keys are:
|
||||
- `use`
|
||||
- `foreach`
|
||||
- `interrupt`
|
||||
- `join`
|
||||
|
||||
Zero kind keys or multiple kind keys are validation errors.
|
||||
|
||||
@@ -243,19 +242,6 @@ This lowers to the current core `ForeachNode`.
|
||||
|
||||
This lowers to the current core `InterruptNode`.
|
||||
|
||||
### `join`
|
||||
|
||||
```json
|
||||
{
|
||||
"join": {}
|
||||
}
|
||||
```
|
||||
|
||||
This lowers to the current core `JoinNode`.
|
||||
|
||||
`join` is not a reverse branch. It remains reserved for actual join/frame
|
||||
semantics.
|
||||
|
||||
## Routes
|
||||
|
||||
Most ordinary edges should be authored through `routes`:
|
||||
@@ -337,7 +323,8 @@ node_c.unreachable
|
||||
-> runtime_error
|
||||
```
|
||||
|
||||
This is not `join`. It is compressed declaration of several ordinary edges.
|
||||
This is not synchronization. It is compressed declaration of several ordinary
|
||||
edges.
|
||||
|
||||
Possible later surfaces:
|
||||
|
||||
@@ -366,7 +353,7 @@ That should be handled as its own pass, not smuggled into this MCP draft change.
|
||||
Potential later core work:
|
||||
|
||||
- true graph-as-node / subgraph support
|
||||
- meaningful join semantics
|
||||
- explicit fork/gather semantics
|
||||
- future START-edge support if `Workflow.start` changes
|
||||
|
||||
### Draft `route` Sugar
|
||||
|
||||
@@ -157,7 +157,6 @@ Example:
|
||||
"SubgraphNode",
|
||||
"ConditionNode",
|
||||
"ForeachNode",
|
||||
"JoinNode",
|
||||
"EndNode",
|
||||
"InterruptNode"
|
||||
]
|
||||
|
||||
@@ -85,8 +85,8 @@ semantic operation produces one patch and consumes one revision.
|
||||
clients do not need to know about the internal service split.
|
||||
|
||||
The service boundary is intentionally not capability-only. The current draft
|
||||
model also represents `end`, `condition`, `interrupt`, `foreach`, `join`,
|
||||
`when`, `choose`, and `match` steps, and core may gain more step kinds. This
|
||||
model also represents `end`, `condition`, `interrupt`, `foreach`, `when`,
|
||||
`choose`, `match`, and subgraph steps, and core may gain more step kinds. This
|
||||
slice adds semantic operations only where required, but new step-kind helpers
|
||||
belong in `WorkflowDraftAuthoringApi` rather than a parallel authoring system.
|
||||
|
||||
|
||||
@@ -132,7 +132,6 @@ Node presentation distinguishes the existing core node kinds:
|
||||
- condition;
|
||||
- interrupt;
|
||||
- foreach;
|
||||
- join;
|
||||
- end and other control nodes.
|
||||
|
||||
Each node shows its stable id and concise semantic label. Selecting a node opens
|
||||
@@ -226,4 +225,3 @@ The slice is complete when:
|
||||
7. stale requests and partial failures cannot corrupt newer selections;
|
||||
8. the `lda_report_workflow` lifecycle is readable without scrolling raw JSON;
|
||||
9. frontend tests, typecheck, production build, and optional live smoke pass.
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ deliberate authoring vocabulary that is later lowered by
|
||||
- `DraftUseStep`
|
||||
- `DraftForeachStep`
|
||||
- `DraftInterruptStep`
|
||||
- `DraftJoinStep`
|
||||
- `DraftEndStep`
|
||||
- `DraftWhenStep`
|
||||
- `DraftChooseStep`
|
||||
@@ -149,7 +148,6 @@ Declared top-level outcomes are:
|
||||
- `foreach`: `loop`, `done`, plus `completed_with_errors` when the item-error
|
||||
policy is `skip` or `collect`;
|
||||
- `interrupt`: `interrupt.outcomes`;
|
||||
- `join`: `done`;
|
||||
- `subgraph`: `subgraph.outcomes`.
|
||||
|
||||
The capability helper remains distinct because it resolves a capability,
|
||||
@@ -175,7 +173,7 @@ reject malformed or ambiguous step objects before dispatching to the API.
|
||||
|
||||
The Python RPC client implements the same method on `WorkflowApi`. Client and
|
||||
server serialize steps with aliases so fields such as foreach `as` and when
|
||||
`if` retain their canonical wire names. Round-trip tests cover all nine step
|
||||
`if` retain their canonical wire names. Round-trip tests cover all eight step
|
||||
variants, including interrupt schemas and subgraph workflow references.
|
||||
|
||||
## CLI Shape
|
||||
@@ -186,7 +184,6 @@ Register a focused Typer application beneath `wf draft`:
|
||||
wf draft add capability
|
||||
wf draft add interrupt
|
||||
wf draft add foreach
|
||||
wf draft add join
|
||||
wf draft add end
|
||||
wf draft add when
|
||||
wf draft add choose
|
||||
@@ -210,7 +207,6 @@ Variant-specific options are:
|
||||
`--resume LOCAL_SOURCE=STATE_TARGET`, and repeatable `--outcome`;
|
||||
- `foreach`: `--over`, `--as`, `--mode`, `--item-error`, optional
|
||||
`--collect-to`, `--max-active`, and `--max-outstanding`;
|
||||
- `join`: no variant-specific options;
|
||||
- `end`: `--outcome` and no `--route`;
|
||||
- `when`: `--condition-file`, `--then`, and `--otherwise`;
|
||||
- `choose`: `--clauses-file` containing the ordered clause array and
|
||||
@@ -269,7 +265,7 @@ modules need them; avoid a broad CLI refactor.
|
||||
|
||||
### CLI
|
||||
|
||||
- `wf draft add --help` lists all nine commands.
|
||||
- `wf draft add --help` lists all eight commands.
|
||||
- Per-command help exposes only relevant options.
|
||||
- Every command builds the expected `DraftStep`, incoming source, and routes.
|
||||
- Invalid flag combinations fail before calling the API.
|
||||
|
||||
@@ -28,7 +28,7 @@ The remaining graph-authoring work is split into independently useful slices:
|
||||
1. selected-step input and output dataflow;
|
||||
2. workflow Input, State, and Outcomes contract projections;
|
||||
3. explicit End authoring and a typed Add step palette;
|
||||
4. typed interrupt, control, subgraph, foreach, and join forms; and
|
||||
4. typed interrupt, control, subgraph, and foreach forms; and
|
||||
5. direct graph gestures lowered through the same canonical mutations.
|
||||
|
||||
This document specifies only the first item.
|
||||
|
||||
@@ -56,7 +56,7 @@ Slice 6 includes:
|
||||
Slice 6 excludes:
|
||||
|
||||
- explicit End-node creation;
|
||||
- typed creation forms for interrupt, condition, subgraph, foreach, or join;
|
||||
- typed creation forms for interrupt, condition, subgraph, or foreach;
|
||||
- graph gesture binding by drawing edges;
|
||||
- arbitrary schema inference from runtime values;
|
||||
- renaming existing step ids;
|
||||
@@ -140,7 +140,7 @@ independent source of truth once the operation is available.
|
||||
Standard frame context currently includes values such as prior outcome, active
|
||||
incoming edge, scope id, lineage id, and parent lineage id. Foreach iteration
|
||||
frames additionally expose loop item, loop index, and the configured foreach
|
||||
alias. Future fork/join features may add branch-scoped context through the same
|
||||
alias. Future fork/gather features may add branch-scoped context through the same
|
||||
inventory without changing high-level clients.
|
||||
|
||||
Context availability is computed by core/API code using workflow graph and
|
||||
|
||||
@@ -36,7 +36,7 @@ They are runtime policy, not workflow graph semantics.
|
||||
|
||||
**Step Attempt** is one admitted attempt to execute a selected workflow `Step`
|
||||
in one frame. Node uses, conditions, foreach controllers, subgraph boundaries,
|
||||
interrupt nodes, joins, and explicit end nodes all count.
|
||||
interrupt nodes, and explicit end nodes all count.
|
||||
|
||||
**Step Number** is the one-based ordinal assigned to an admitted step attempt
|
||||
within a run.
|
||||
@@ -256,7 +256,7 @@ with the run.
|
||||
### Core counting
|
||||
|
||||
- A budget of one admits exactly one step and denies the second.
|
||||
- Node, condition, foreach, subgraph, interrupt, join, and explicit end steps
|
||||
- Node, condition, foreach, subgraph, interrupt, and explicit end steps
|
||||
count.
|
||||
- A transition to legacy `END` does not create an extra attempt.
|
||||
- Handler failure still consumes its admitted step.
|
||||
|
||||
+1
-1
@@ -444,7 +444,7 @@ Use `set-route` separately for outcome routing.
|
||||
Use `wf draft add` to add one typed step to an existing draft:
|
||||
|
||||
```text
|
||||
capability interrupt foreach join end
|
||||
capability interrupt foreach end
|
||||
when choose match subgraph
|
||||
```
|
||||
|
||||
|
||||
+5
-16
@@ -399,8 +399,8 @@ are part of the graph definition:
|
||||
```
|
||||
|
||||
Static values are not path mappings. Use `{"target": ..., "value": ...}` for
|
||||
literal JSON values. Invalid draft step shapes are rejected instead of silently
|
||||
compiling to `join`.
|
||||
literal JSON values. Invalid draft step shapes are rejected instead of being
|
||||
silently replaced with a placeholder step.
|
||||
|
||||
Generated MCP tool wrappers are intentionally naive. They normally expose both
|
||||
`ok` and `error` outcomes, because MCP tool calls can report transport/provider
|
||||
@@ -513,16 +513,6 @@ Declares an explicit workflow terminal outcome.
|
||||
Use explicit `end` steps for non-`ok` workflow outcomes. The legacy `__end__`
|
||||
destination remains the shorthand for public workflow outcome `ok`.
|
||||
|
||||
### `join`
|
||||
|
||||
Joins control flow.
|
||||
|
||||
```json
|
||||
{
|
||||
"join": {}
|
||||
}
|
||||
```
|
||||
|
||||
### `when`
|
||||
|
||||
Creates one boolean decision step. The condition uses the same JSON shape as
|
||||
@@ -643,10 +633,9 @@ interrupt, an end step, or a subgraph rather than a capability:
|
||||
|
||||
```bash
|
||||
wf draft create report_ws --name report_workflow
|
||||
wf draft add join report_ws --revision 1 --step gate --route done=finish
|
||||
wf draft set-start report_ws --revision 2 --step gate
|
||||
wf draft add end report_ws --revision 3 --step finish --outcome error
|
||||
wf draft set-contract report_ws --revision 4 --outcome error
|
||||
wf draft add end report_ws --revision 1 --step finish --outcome error
|
||||
wf draft set-start report_ws --revision 2 --step finish
|
||||
wf draft set-contract report_ws --revision 3 --outcome error
|
||||
wf draft validate report_ws
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user