docs changes

This commit is contained in:
lda
2026-05-21 14:45:05 +07:00 Verified
parent 23ffddf9b3
commit c3556c4815
5 changed files with 111 additions and 35 deletions
+60 -17
View File
@@ -42,15 +42,20 @@ Examples:
```json ```json
{ {
"input": [ "input": [
{"target": "user.name", "path": "state.person.name"}, {
{"target": "user.email", "path": "state.digital.email"}, "target": {"root": "local", "parts": ["user", "name"]},
{"target": "job.title", "path": "state.job.title"}, "path": {"root": "state", "parts": ["person", "name"]}
{"target": "mode", "value": "fast"} },
{
"target": {"root": "local", "parts": ["mode"]},
"value": "fast"
}
], ],
"output": [ "output": [
{"source": "job.wage", "target": "state.job.wage"}, {
{"source": "job.years", "target": "state.experience.years"}, "source": {"root": "local", "parts": ["job", "wage"]},
{"source": "user.age", "target": "state.person.age"} "target": {"root": "state", "parts": ["job", "wage"]}
}
] ]
} }
``` ```
@@ -59,8 +64,18 @@ Whole-object mapping remains valid:
```json ```json
{ {
"input": [{"target": "user", "path": "state.person"}], "input": [
"output": [{"source": "user", "target": "state.person"}] {
"target": {"root": "local", "parts": ["user"]},
"path": {"root": "state", "parts": ["person"]}
}
],
"output": [
{
"source": {"root": "local", "parts": ["user"]},
"target": {"root": "state", "parts": ["person"]}
}
]
} }
``` ```
@@ -68,8 +83,18 @@ Whole-payload mapping uses the local root path `"."`:
```json ```json
{ {
"input": [{"target": ".", "path": "state.rates"}], "input": [
"output": [{"source": ".", "target": "state.rates"}] {
"target": {"root": "local", "parts": []},
"path": {"root": "state", "parts": ["rates"]}
}
],
"output": [
{
"source": {"root": "local", "parts": []},
"target": {"root": "state", "parts": ["rates"]}
}
]
} }
``` ```
@@ -96,8 +121,14 @@ Valid:
```json ```json
[ [
{"target": "user.name", "path": "state.person.name"}, {
{"target": "user.email", "path": "state.person.email"} "target": {"root": "local", "parts": ["user", "name"]},
"path": {"root": "state", "parts": ["person", "name"]}
},
{
"target": {"root": "local", "parts": ["user", "email"]},
"path": {"root": "state", "parts": ["person", "email"]}
}
] ]
``` ```
@@ -105,8 +136,14 @@ Invalid:
```json ```json
[ [
{"target": "user", "path": "state.person"}, {
{"target": "user.name", "path": "state.person.name"} "target": {"root": "local", "parts": ["user"]},
"path": {"root": "state", "parts": ["person"]}
},
{
"target": {"root": "local", "parts": ["user", "name"]},
"path": {"root": "state", "parts": ["person", "name"]}
}
] ]
``` ```
@@ -122,8 +159,14 @@ Invalid:
```json ```json
[ [
{"source": "user", "target": "state.person"}, {
{"source": "user.name", "target": "state.person.name"} "source": {"root": "local", "parts": ["user"]},
"target": {"root": "state", "parts": ["person"]}
},
{
"source": {"root": "local", "parts": ["user", "name"]},
"target": {"root": "state", "parts": ["person", "name"]}
}
] ]
``` ```
@@ -1,5 +1,9 @@
# Path And Mapping Scratch # Path And Mapping Scratch
> Historical note: this scratchpad records how the mapping model evolved.
> Current core behavior uses canonical `input`/`output` and interrupt
> `request`/`resume` binding lists. See `core_state_mapping_and_merge.md`.
This is a focused scratchpad for the `wf_core` path/mapping design thread. This is a focused scratchpad for the `wf_core` path/mapping design thread.
Clean this into real docs later. Clean this into real docs later.
@@ -1,5 +1,9 @@
# Graph as struct? workflow as struct # Graph as struct? workflow as struct
> Historical note: this file preserves older design notes. Current binding
> shapes are documented in `core_state_mapping_and_merge.md`,
> `structural_refs.md`, and `workflow_drafts.md`.
This file is now mostly a working design note. This file is now mostly a working design note.
The original top section was rough brainstorming around a few ideas that did end The original top section was rough brainstorming around a few ideas that did end
+7 -5
View File
@@ -71,15 +71,17 @@ limits and intended adapter seam.
## What This Cleanup Does Not Solve Yet ## What This Cleanup Does Not Solve Yet
- Node-local mapping paths are still top-level only in the current runtime. - Node-local input/output bindings now support nested local paths and atomic
The intended direction for nested node-local paths, patch commits, and future state patch commits. The remaining mapping design notes for future reducer
nested merge metadata is documented in metadata are documented in
[`core_state_mapping_and_merge.md`](core_state_mapping_and_merge.md). [`core_state_mapping_and_merge.md`](core_state_mapping_and_merge.md).
- Foreach is still serial-only. Parallel foreach needs an explicit scheduling - Foreach is still serial-only. Parallel foreach needs an explicit scheduling
model, not just `asyncio.gather`. model, not just `asyncio.gather`. `ForeachNode.over` is typed as a
`GraphSourcePath`, but execution is still serial.
- Interrupt lifecycle is still node-level and run-state-level. Long-lived - Interrupt lifecycle is still node-level and run-state-level. Long-lived
external subscriptions or notification streams need a separate lifecycle external subscriptions or notification streams need a separate lifecycle
design. design. Interrupt `request` and `resume` are canonical binding lists; nested
child-workflow resume is still future work.
- Native subgraphs are not part of `wf_core` yet. The core `Step` model only - Native subgraphs are not part of `wf_core` yet. The core `Step` model only
includes node, condition, foreach, join, and interrupt steps; `Workflow` does includes node, condition, foreach, join, and interrupt steps; `Workflow` does
not contain nested workflow/subgraph steps. not contain nested workflow/subgraph steps.
+36 -13
View File
@@ -8,7 +8,7 @@
- [docs/schema_validation.md](docs/schema_validation.md): current payload schema validation limits and intended validation seam. - [docs/schema_validation.md](docs/schema_validation.md): current payload schema validation limits and intended validation seam.
- [docs/wf_mcp_plan.md](docs/wf_mcp_plan.md): `wf_mcp` direction as a namespaced MCP capability broker plus workflow build/run layer. - [docs/wf_mcp_plan.md](docs/wf_mcp_plan.md): `wf_mcp` direction as a namespaced MCP capability broker plus workflow build/run layer.
- [docs/wf_mcp_architecture.md](docs/wf_mcp_architecture.md): current `wf_mcp` package boundaries and dependency rules. - [docs/wf_mcp_architecture.md](docs/wf_mcp_architecture.md): current `wf_mcp` package boundaries and dependency rules.
- [docs/scratchpad.md](docs/scratchpad.md): rougher design history and intermediate spec notes that fed the current model. - [docs/historical/scratchpad.md](docs/historical/scratchpad.md): historical design notes that fed the current model.
## What is this ## What is this
@@ -112,19 +112,42 @@ NodeUse
.type: "node" .type: "node"
.node // reference to NodeDef .node // reference to NodeDef
.desc? .desc?
.in_map // graph path -> node input field .input[] // graph/value -> node-local input bindings
.out_map // node output field -> graph state path .output[] // node-local output -> graph state bindings
.retry? // optional override .retry? // optional override
.timeout_seconds? // optional override .timeout_seconds? // optional override
``` ```
The node does not get ambient access to all workflow state. It receives: The node does not get ambient access to all workflow state. It receives:
- mapped input - the payload built by explicit `input` bindings
- runtime context - runtime context
This keeps nodes reusable instead of graph-coupled. This keeps nodes reusable instead of graph-coupled.
Path bindings use structural paths in saved JSON:
```json
{
"input": [
{
"target": {"root": "local", "parts": ["text"]},
"path": {"root": "input", "parts": ["text"]}
}
],
"output": [
{
"source": {"root": "local", "parts": ["echoed"]},
"target": {"root": "state", "parts": ["echoed"]}
}
]
}
```
Legacy `in_map`, `input_values`, and `out_map` shapes remain parse-only
compatibility inputs. New authored or saved plans should write `input` and
`output`.
### Control-flow nodes ### Control-flow nodes
#### **ConditionNode** #### **ConditionNode**
@@ -161,8 +184,8 @@ Conditions are structured JSON, not freeform code strings.
.id .id
.type: "interrupt" .type: "interrupt"
.kind // approval | text_input | choice | tool_auth | ... .kind // approval | text_input | choice | tool_auth | ...
.request_map // graph state/input path -> interrupt payload field .request[] // graph/value -> public interrupt payload bindings
.out_map // resume payload field -> graph state path .resume[] // resume payload -> graph state bindings
.outcomes[] // ex: submitted, cancelled .outcomes[] // ex: submitted, cancelled
``` ```
@@ -247,9 +270,9 @@ State fields carry metadata, especially merge behavior.
```text ```text
StateField StateField
.type .path
.merge_strategy // replace | append | merge_object .schema // JSON Schema with reducer extension metadata
.trace? .reducer // wf.std.replace | wf.std.append | ...
``` ```
Rules: Rules:
@@ -272,7 +295,7 @@ Executor steps:
2. Validate workflow input 2. Validate workflow input
3. Copy input into state 3. Copy input into state
4. Start at the declared `start` node 4. Start at the declared `start` node
5. Resolve node input snapshot from `in_map` 5. Resolve node input snapshot from canonical `input` bindings
6. Execute node with mapped input plus runtime context 6. Execute node with mapped input plus runtime context
7. Validate typed node output 7. Validate typed node output
8. Commit mapped output into state 8. Commit mapped output into state
@@ -394,7 +417,7 @@ Resume should not jump back into the middle of arbitrary Python code.
Instead: Instead:
- resume data is delivered to the interrupt node - resume data is delivered to the interrupt node
- the interrupt node maps resume fields back into state through explicit `out_map` - the interrupt node maps resume fields back into state through explicit `resume` bindings
- graph routing continues normally from that node - graph routing continues normally from that node
This means the primary interrupt design is node-based, not line-based. This means the primary interrupt design is node-based, not line-based.
@@ -463,8 +486,8 @@ Before execution, the validator should be able to check:
- every edge outcome is declared by its source node - every edge outcome is declared by its source node
- each source + outcome pair is wired at most once - each source + outcome pair is wired at most once
- every reachable outcome is wired - every reachable outcome is wired
- every `in_map` destination exists in node input schema - every `input` binding target is a valid node-local path
- every `out_map` source exists in node output schema - every `output` binding source exists in node output schema where schema detail is known
- every condition path references valid `input`, `state`, or `context` - every condition path references valid `input`, `state`, or `context`
- every `foreach.over` path references valid `input` or `state` - every `foreach.over` path references valid `input` or `state`