ai-workflow-flow-dsl-reference 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/index.d.ts +8 -0
  2. package/dist/index.js +18 -0
  3. package/dist/resource-module/KindDefinitions/WikiPage/manifest.xnl +10 -0
  4. package/dist/resource-module/WikiPages/README/manifest.xnl +6 -0
  5. package/dist/resource-module/WikiPages/foundation__depa-axioms/manifest.xnl +6 -0
  6. package/dist/resource-module/WikiPages/foundation__naming-axioms/manifest.xnl +6 -0
  7. package/dist/resource-module/WikiPages/foundation__syntax-axioms/manifest.xnl +6 -0
  8. package/dist/resource-module/WikiPages/spec__ai-workflow__ctrl-workflow/manifest.xnl +6 -0
  9. package/dist/resource-module/WikiPages/spec__ai-workflow__data-workflow/manifest.xnl +6 -0
  10. package/dist/resource-module/WikiPages/spec__ai-workflow__resources/manifest.xnl +6 -0
  11. package/dist/resource-module/WikiPages/spec__bp-ctrl-flow__domains/manifest.xnl +6 -0
  12. package/dist/resource-module/WikiPages/spec__bp-ctrl-flow__nodes/manifest.xnl +6 -0
  13. package/dist/resource-module/WikiPages/spec__eager-data-flow__domains/manifest.xnl +6 -0
  14. package/dist/resource-module/WikiPages/spec__eager-data-flow__files/manifest.xnl +6 -0
  15. package/dist/resource-module/WikiPages/spec__eager-data-flow__nodes/manifest.xnl +6 -0
  16. package/dist/resource-module/WikiPages/spec__eager-data-flow__refs/manifest.xnl +6 -0
  17. package/dist/resource-module/WikiPages/spec__flow-core__domains/manifest.xnl +6 -0
  18. package/dist/resource-module/WikiPages/spec__flow-core__files/manifest.xnl +6 -0
  19. package/dist/resource-module/WikiPages/spec__flow-core__nodes/manifest.xnl +6 -0
  20. package/dist/resource-module/WikiPages/spec__flow-core__orchestration/manifest.xnl +6 -0
  21. package/dist/resource-module/WikiPages/spec__flow-core__refs/manifest.xnl +6 -0
  22. package/dist/resource-module/WikiPages/spec__instant-ctrl-flow__domains/manifest.xnl +6 -0
  23. package/dist/resource-module/WikiPages/spec__instant-ctrl-flow__nodes/manifest.xnl +6 -0
  24. package/dist/resource-module/WikiPages/spec__work-ctrl-flow__domains/manifest.xnl +6 -0
  25. package/dist/resource-module/WikiPages/spec__work-ctrl-flow__nodes/manifest.xnl +6 -0
  26. package/dist/resource-module/WikiPages/std__ai-ctrl-workflow__axioms/manifest.xnl +6 -0
  27. package/dist/resource-module/WikiPages/std__ai-data-workflow__axioms/manifest.xnl +6 -0
  28. package/dist/resource-module/WikiPages/std__behavior-tree__axioms/manifest.xnl +6 -0
  29. package/dist/resource-module/WikiPages/std__bp-ctrl-flow__axioms/manifest.xnl +6 -0
  30. package/dist/resource-module/WikiPages/std__eager-data-flow__axioms/manifest.xnl +6 -0
  31. package/dist/resource-module/WikiPages/std__instant-ctrl-flow__axioms/manifest.xnl +6 -0
  32. package/dist/resource-module/WikiPages/std__work-ctrl-flow__axioms/manifest.xnl +6 -0
  33. package/dist/resource-module/content/.depa-flow-dsl-provenance.json +127 -0
  34. package/dist/resource-module/content/README.md +164 -0
  35. package/dist/resource-module/content/foundation/depa-axioms.md +41 -0
  36. package/dist/resource-module/content/foundation/naming-axioms.md +167 -0
  37. package/dist/resource-module/content/foundation/syntax-axioms.md +60 -0
  38. package/dist/resource-module/content/spec/ai-workflow/ctrl-workflow.md +53 -0
  39. package/dist/resource-module/content/spec/ai-workflow/data-workflow.md +78 -0
  40. package/dist/resource-module/content/spec/ai-workflow/resources.md +242 -0
  41. package/dist/resource-module/content/spec/bp-ctrl-flow/domains.md +30 -0
  42. package/dist/resource-module/content/spec/bp-ctrl-flow/nodes.md +122 -0
  43. package/dist/resource-module/content/spec/eager-data-flow/domains.md +59 -0
  44. package/dist/resource-module/content/spec/eager-data-flow/files.md +68 -0
  45. package/dist/resource-module/content/spec/eager-data-flow/nodes.md +151 -0
  46. package/dist/resource-module/content/spec/eager-data-flow/refs.md +90 -0
  47. package/dist/resource-module/content/spec/flow-core/domains.md +39 -0
  48. package/dist/resource-module/content/spec/flow-core/files.md +50 -0
  49. package/dist/resource-module/content/spec/flow-core/nodes.md +203 -0
  50. package/dist/resource-module/content/spec/flow-core/orchestration.md +161 -0
  51. package/dist/resource-module/content/spec/flow-core/refs.md +78 -0
  52. package/dist/resource-module/content/spec/instant-ctrl-flow/domains.md +20 -0
  53. package/dist/resource-module/content/spec/instant-ctrl-flow/nodes.md +47 -0
  54. package/dist/resource-module/content/spec/work-ctrl-flow/domains.md +29 -0
  55. package/dist/resource-module/content/spec/work-ctrl-flow/nodes.md +90 -0
  56. package/dist/resource-module/content/std/ai-ctrl-workflow/axioms.md +31 -0
  57. package/dist/resource-module/content/std/ai-data-workflow/axioms.md +24 -0
  58. package/dist/resource-module/content/std/behavior-tree/axioms.md +72 -0
  59. package/dist/resource-module/content/std/bp-ctrl-flow/axioms.md +48 -0
  60. package/dist/resource-module/content/std/eager-data-flow/axioms.md +57 -0
  61. package/dist/resource-module/content/std/instant-ctrl-flow/axioms.md +37 -0
  62. package/dist/resource-module/content/std/work-ctrl-flow/axioms.md +54 -0
  63. package/dist/resource-module/manifest.xnl +9 -0
  64. package/package.json +29 -0
@@ -0,0 +1,122 @@
1
+ # L3 · BPCtrlFlow statements 与 TaskSpace
2
+
3
+ > BPCtrlFlow 继承[共享 CtrlFlow statements](../flow-core/nodes.md)及 [WorkCtrlFlow statements/resume](../work-ctrl-flow/nodes.md),只增加 `TaskStep` statement 与 TaskSpace domain nodes。
4
+
5
+ ## `<BPCtrlFlow>` definition
6
+
7
+ 根 `[]` 直接保存有序 statements。TaskStepResult 沿公共 data chain 进入后续 `If`:
8
+
9
+ ```xnl
10
+ <BPCtrlFlow #depa.flows.demo.ExpenseApproval apiVersion="depa.flows/v1" version="1.0.0" [
11
+ <TaskStep #manager-approval {
12
+ task = "task-space://#task_manager_approve"
13
+ }>
14
+ <If #route-manager-result (
15
+ <Branches [
16
+ <Branch #approved {
17
+ when = "vfs://./flow-code/approval.ts#isApproved"
18
+ } [
19
+ <Run #start-payout {
20
+ src = "vfs://./flow-code/approval.ts#startPayout"
21
+ }>
22
+ <Return #approved-result>
23
+ ]>
24
+ <Branch #forwarded {
25
+ when = "vfs://./flow-code/approval.ts#isForwarded"
26
+ } [
27
+ <Return #forwarded-result>
28
+ ]>
29
+ <Otherwise [
30
+ <Return #refused-result>
31
+ ]>
32
+ ]>
33
+ )>
34
+ ]>
35
+ ```
36
+
37
+ ```ts
38
+ export function isApproved(runtime, input, config) {
39
+ return input.outcome === 'approved';
40
+ }
41
+
42
+ export function isForwarded(runtime, input, config) {
43
+ return input.outcome === 'forwarded';
44
+ }
45
+ ```
46
+
47
+ predicate 与 `startPayout` 都遵守 `output = fn(runtime, input, config)`。没有审批专用 expression 或节点结果分支。
48
+
49
+ ## `<TaskStep>`
50
+
51
+ | 字段 | 必填 | 说明 |
52
+ |---|---:|---|
53
+ | `#id` | 是 | 构成稳定 statement path 与任务 WaitHandle identity |
54
+ | `task` | 是 | `"task-space://#<id>"`,目标是 TaskSpace 直接子节点 |
55
+ | `config` | 否 | 静态 statement config,缺省 `{}` |
56
+
57
+ 首次进入时 TaskStep 激活绑定任务并持久挂起。任务操作恢复后,statement 正常输出:
58
+
59
+ ```ts
60
+ interface TaskStepResult<Payload = unknown> {
61
+ taskId: string;
62
+ status: 'Done' | 'Refused' | 'Forwarded' | 'Abandoned';
63
+ outcome: 'approved' | 'refused' | 'forwarded' | 'abandoned';
64
+ payload?: Payload;
65
+ }
66
+ ```
67
+
68
+ 四种 outcome 都是 data。`Refused` 不产生技术 Failure,`Forwarded` 也不伪装成 Success 控制信号;下一条普通 `If` 决定业务路径。TaskStep 没有 `assignTo`,也没有私有 Hooks authoring;前后副作用用相邻 `Run` statement 显式表达。
69
+
70
+ 非法任务迁移、TaskSpace store 错误或损坏的恢复消息才走技术 fault 通道。等待合法人工操作是 suspension。Fallback 只能捕获前述 fault,不能消费 `TaskStepResult.outcome`。
71
+
72
+ ## `<TaskSpace>` / `<TaskGroup>` / `<Task>`
73
+
74
+ 任务子节点直接放父节点的 `[]`;没有 `SubNodes` wrapper:
75
+
76
+ ```xnl
77
+ <TaskSpace #space_expense_approval version=1 { name = "费用审批任务空间" } [
78
+ <Task #task_manager_approve {
79
+ name = "直属主管审批"
80
+ ownerAccount = "user:manager"
81
+ status = "NotStarted"
82
+ order = 0
83
+ }>
84
+ <TaskGroup #grp_finance {
85
+ name = "财务复核"
86
+ executionMode = "ALL"
87
+ order = 1
88
+ } [
89
+ <Task #task_finance_approve {
90
+ name = "财务审批"
91
+ ownerAccount = "group:finance"
92
+ status = "NotStarted"
93
+ order = 0
94
+ }>
95
+ ]>
96
+ ]>
97
+ ```
98
+
99
+ | node | metadata | `{}` fields | `[]` |
100
+ |---|---|---|---|
101
+ | `TaskSpace` | `version` | `name` | direct Task / TaskGroup |
102
+ | `TaskGroup` | - | `name`, `executionMode = SEQUENTIAL | ANY | ALL`, `order` | nested Task / TaskGroup |
103
+ | `Task` | - | `name`, `ownerAccount`, `status`, `order`, optional `description` | none |
104
+
105
+ 基础状态机:
106
+
107
+ ```text
108
+ NotStarted -> Active | Abandoned
109
+ Active -> Done | Refused | Forwarded | Delegated | NotStarted | Abandoned
110
+ Delegated -> Active | Abandoned
111
+ Done / Refused / Forwarded / Abandoned = terminal
112
+ ```
113
+
114
+ approve 操作把任务推进到 `Done`,并由 TaskStep 投影为 `outcome = "approved"`。TaskGroup 按 executionMode 聚合子任务并输出同形 TaskStepResult;聚合细节属于任务域,不改变 CtrlFlow grammar。
115
+
116
+ ## Validation And Rejections
117
+
118
+ - `TaskStep.task` 必须解析到当前 bundle TaskSpace 的直接子节点;同一任务不能绑定多个 TaskStep。
119
+ - `TaskStep` 只能出现在 BPCtrlFlow definition,且必须有稳定唯一 `#id`。
120
+ - `status`、`executionMode` 与状态迁移必须合法;运行期事实不得回写 definition。
121
+ - authoring 中出现 `Tree`、`Sequence`、`Selector`、`Condition`、`action.types`、`SubNodes` 或 `assignTo` 必须拒绝。
122
+ - 每个 `src` / `when` export 都必须遵守 `output = fn(runtime, input, config)`;predicate output 必须是 boolean。
@@ -0,0 +1,59 @@
1
+ # L3 · EagerDataFlow 事实与域
2
+
3
+ > EagerDataFlow definition 是 topology、node config 和 contract 的唯一 authoring 真源。编译 plan、invocation state 与 editor layout 都不能反向覆盖它。
4
+
5
+ ## Authoring Facts
6
+
7
+ | owner | file / projection | root | entries / scheme | 语义 |
8
+ |---|---|---|---|---|
9
+ | flow definition | 单文件或 `manifest.xnl` | `EagerDataFlow` | 根 `[]` 中五种 DAG node | 唯一 topology 与 node config 真源 |
10
+ | flow contract | 根 `()` 内联或 `flow.contract.xnl` | `FlowContract` | 无 entry scheme | 公开 input/output type 与 ports |
11
+ | `config` | `config.xnl` | `Config` | `ConfigEntry` / `config://` | 可选静态配置事实 |
12
+ | `config.def` | `config.def.xnl` | `ConfigDef` | `ConfigEntryDef` / `config-def://` | 可选 config shape facet |
13
+ | `flow.authoring` | 根 `()` 内联或 `flow.authoring.xnl` | `FlowAuthoring` | `NodeLayout` / `flow-authoring://` | layout/viewport;不得复制 topology |
14
+
15
+ `FlowContract` 在一个 definition 中恰好一个;`FlowAuthoring` 至多一个。它们是根 `()` 的不同唯一子域,不进入 DAG node `[]`。根 metadata、`{}` 配置、`()` 唯一子域与 `[]` 节点列表不得混写。
16
+
17
+ ## Derived Plan
18
+
19
+ loader/compiler 可以从 definition 派生纯 serializable plan:
20
+
21
+ ```text
22
+ EagerDataFlowAuthoringPlan
23
+ contract
24
+ nodes / nodeById
25
+ dataEdges
26
+ waitForEdges
27
+ subflowEdges
28
+ diagnostics
29
+ ```
30
+
31
+ `dataEdges` 来自 inputs 的 `flow-port://`;`waitForEdges` 来自 `flow-node://`;`subflowEdges` 来自 SubFlowNode.flow。三者不能被写入额外 authoring 文件,也不能把 dataEdges 与 waitForEdges 合并成丢失来源的单一列表。
32
+
33
+ ## Runtime Facts
34
+
35
+ | fact | owner | 生命周期 |
36
+ |---|---|---|
37
+ | invocation input/output | EagerDataFlow caller/runner | 单次调用 |
38
+ | node status、ready set、published ports | invocation scheduler | 单次调用,不回写 XNL |
39
+ | completion facts、faults、cancellation | invocation scheduler/runtime | 单次调用 |
40
+ | child invocation state | target EagerDataFlow runner | SubFlowNode 调用期间隔离 |
41
+ | effect state | runtime/effect owner | 由 effect 契约决定,flow 不复制 |
42
+
43
+ EagerDataFlow 没有持久 snapshot、resume message、signal store 或 seed。若进程中断,是否由调用者重新发起取决于外部幂等策略;definition 本身不承诺 WorkCtrlFlow 式恢复。
44
+
45
+ ## 与 lazy DataGraph 的边界
46
+
47
+ | EagerDataFlow | lazy signal DataGraph |
48
+ |---|---|
49
+ | 公开可执行 root,显式调用 | 由 Scope materialize/mount 的长生命周期 graph |
50
+ | 固定 invocation input,节点最多运行一次 | Signal/state 变化可 invalidation 并重算 |
51
+ | flow-port data edge + flow-node completion edge | module local slot deps 与 reactive subscription |
52
+ | Entry/Transform/Sink/SubFlow/Return | Signal/Computed/Processor/Async/Consumer |
53
+ | 全 DAG 收敛后终止 | graph object 持续存活 |
54
+
55
+ 两者不共享 root、节点 tag、引用或 runtime state。DataGraph 不能作为 EagerDataFlow 的隐式 input source;需要交互时,由 caller/runtime 显式读取 graph 后形成 flow invocation input,或把 flow output 显式写回 graph。
56
+
57
+ ## Rejected Authoring Facts
58
+
59
+ `DataFlow` 旧根、DataGraph module/seed/bindings、BehaviorTreePlan、运行期 ready/status/port value 都不是 EagerDataFlow authoring domain。`DataFlow` 只能出现在 removed/rejected 说明中,loader 不提供 alias 或兼容解析。
@@ -0,0 +1,68 @@
1
+ # L3 · EagerDataFlow 文件组织
2
+
3
+ ## 单文件 definition
4
+
5
+ 小型 EagerDataFlow 可以由一个 XNL 文件承载。文件名不决定类别;`EagerDataFlow` 根 tag 和根 FQN 才是 identity。
6
+
7
+ ```text
8
+ flows/
9
+ customer-export.xnl
10
+ flow-code/
11
+ export.types.ts
12
+ export.ts
13
+ ```
14
+
15
+ ```xnl
16
+ <EagerDataFlow #depa.flows.demo.CustomerExport apiVersion="depa.flows/v1" version="1.0.0" (
17
+ <FlowContract #depa.flows.demo.CustomerExport {
18
+ inputPorts = ["customers"]
19
+ outputPorts = ["archive"]
20
+ }>
21
+ ) [
22
+ <EntryNode #entry>
23
+ <TransformNode #archive {
24
+ inputs = { customers = "flow-port://#entry/customers" }
25
+ outputs = ["archive"]
26
+ src = "vfs://./flow-code/export.ts#createArchive"
27
+ }>
28
+ <ReturnNode #return {
29
+ inputs = { archive = "flow-port://#archive/archive" }
30
+ }>
31
+ ]>
32
+ ```
33
+
34
+ ## 目录 definition
35
+
36
+ 复杂 flow 使用 folder unit:
37
+
38
+ ```text
39
+ flows/customer-export/
40
+ manifest.xnl # <EagerDataFlow #depa.flows.demo.CustomerExport>
41
+ flow.contract.xnl # 可选外提的唯一 FlowContract 子域
42
+ config.xnl # 可选静态 config
43
+ config.def.xnl # 可选 config shape
44
+ flow.authoring.xnl # 可选布局事实
45
+ flow-code/
46
+ export.types.ts
47
+ export.ts
48
+ ```
49
+
50
+ `manifest.xnl` 是唯一 definition 入口,始终持有根 `[]` 的 node topology。FlowContract 可以内联在根 `()`,也可以按唯一子域外提为 `flow.contract.xnl`;两种形态逻辑等价,不能同时声明。FlowAuthoring 同理可内联或外提,但只保存 layout/viewport。
51
+
52
+ ## 单/多文件边界
53
+
54
+ - 根 tag 必须是 `EagerDataFlow`,`#id` 必须是 FQN;文件名不能创建第二个 identity。
55
+ - 根 `[]` 只直接包含 EntryNode、TransformNode、SinkNode、SubFlowNode、ReturnNode。
56
+ - `FlowContract`、`FlowAuthoring` 进入 `()` 唯一子域区,不得用 `Nodes`、`Graph` 或 `Block` 包装 DAG。
57
+ - `vfs://./...` 相对当前 flow bundle 根解析;单文件和目录形态不改变逻辑引用。
58
+ - code export 保存在 `.ts` 等脚本中,XNL 只保存 `type` / `src` / `impl` 引用。
59
+ - loader/compiler 输出的 plan、edge list、topological order 和运行状态都是可重建派生物,不持久化为 definition 文件。
60
+
61
+ ## Removed File Shapes
62
+
63
+ 以下形态必须拒绝,不能作为兼容入口:
64
+
65
+ - 以 `<DataFlow>` 作为单文件或 manifest 根。
66
+ - `nodes.xnl`、`edges.xnl`、`*.graph.json` 或其他第二份 topology。
67
+ - DataGraph 的 `data.graph.xnl` / `data.graph.seed.xnl` 被当作 EagerDataFlow definition。
68
+ - XNL 中内联函数、表达式或 runtime handler object。
@@ -0,0 +1,151 @@
1
+ # L3 · EagerDataFlow nodes 与执行语义
2
+
3
+ > 本页定义 EagerDataFlow 的公开根、FlowContract、五种节点和 ready scheduling。引用与跨 unit 规则见[引用协议](refs.md),事实 owner 见[域与运行事实](domains.md)。
4
+
5
+ ## 完整 definition
6
+
7
+ ```xnl
8
+ <EagerDataFlow #depa.flows.demo.CustomerExport apiVersion="depa.flows/v1" version="1.0.0" (
9
+ <FlowContract #depa.flows.demo.CustomerExport {
10
+ input = "vfs://./flow-code/export.types.ts#CustomerExportInput"
11
+ output = "vfs://./flow-code/export.types.ts#CustomerExportOutput"
12
+ inputPorts = ["customers"]
13
+ outputPorts = ["archive"]
14
+ }>
15
+ ) [
16
+ <EntryNode #entry>
17
+ <TransformNode #normalize {
18
+ inputs = { customers = "flow-port://#entry/customers" }
19
+ outputs = ["customers"]
20
+ type = "vfs://./flow-code/export.types.ts#NormalizeCustomers"
21
+ src = "vfs://./flow-code/export.ts#normalizeCustomers"
22
+ config = { trimNames = true }
23
+ }>
24
+ <SinkNode #audit {
25
+ inputs = { customers = "flow-port://#normalize/customers" }
26
+ src = "vfs://./flow-code/export.ts#auditCustomers"
27
+ }>
28
+ <TransformNode #archive {
29
+ inputs = { customers = "flow-port://#normalize/customers" }
30
+ outputs = ["archive"]
31
+ waitFor = ["flow-node://#audit"]
32
+ src = "vfs://./flow-code/export.ts#createArchive"
33
+ }>
34
+ <ReturnNode #return {
35
+ inputs = { archive = "flow-port://#archive/archive" }
36
+ }>
37
+ ]>
38
+ ```
39
+
40
+ `()` 中的 FlowContract 是按 tag 唯一的子域;DAG nodes 直接进入根 `[]`,没有 `Nodes` wrapper。节点 `#id` 在当前 definition 内唯一,数组顺序不创建依赖。
41
+
42
+ ## `<FlowContract>`
43
+
44
+ | 字段 | 必填 | 约束 |
45
+ |---|---:|---|
46
+ | `#id` | 是 | 必须等于 EagerDataFlow 根 FQN |
47
+ | `inputPorts` | 是 | 唯一非空 port name 列表;调用 input record 必须恰好匹配 |
48
+ | `outputPorts` | 是 | 唯一非空 port name 列表;公开 output record 必须恰好匹配 |
49
+ | `input` | 否 | `vfs://...#Export`,描述完整 input record type |
50
+ | `output` | 否 | `vfs://...#Export`,描述完整 output record type |
51
+
52
+ port name 是节点局部 key,必须匹配 `[A-Za-z_][A-Za-z0-9_-]*`。input/output type 是静态契约,不是 runtime validator 或实现函数;runtime 可以用其派生 validator,但不能把派生物写回 definition。
53
+
54
+ ## 五种节点
55
+
56
+ | node | inputs | outputs | code / target | 完成语义 |
57
+ |---|---|---|---|---|
58
+ | `EntryNode` | 禁止 | 由 contract inputPorts 派生 | 禁止 | invocation input 校验并发布后完成 |
59
+ | `TransformNode` | 必填 map | 必填且唯一的列表 | `type` 可选;实现 binding 必须可解析 | 实现成功返回完整 output record 后完成 |
60
+ | `SinkNode` | 必填 map | 禁止 | `type` 可选;实现 binding 必须可解析 | 实现成功返回 `void` 后只发布 completion fact |
61
+ | `SubFlowNode` | 必须恰好匹配目标 inputPorts | 由目标 outputPorts 派生 | `flow` 必填;禁止 node code | 子 flow 整体成功后发布 outputs 与 completion fact |
62
+ | `ReturnNode` | 必须恰好匹配当前 outputPorts | 禁止 | 禁止 | 捕获公开 output;flow 仍等待本 invocation 的其他节点收敛 |
63
+
64
+ 除 EntryNode 外,节点都可声明 `waitFor = ["flow-node://#..."]`。`inputs` 的 key 是本节点形参名,value 必须是当前 flow 内的 `flow-port://`。一个 input key 只能绑定一个上游 port;多个下游可以读取同一 output port。
65
+
66
+ ## TransformNode / SinkNode 代码协议
67
+
68
+ ```ts
69
+ type EagerNodeCode<Runtime, Input, Config, Output> = (
70
+ runtime: Runtime,
71
+ input: Readonly<Input>,
72
+ config: Readonly<Config>,
73
+ ) => Output | Promise<Output>;
74
+ ```
75
+
76
+ ```ts
77
+ export async function normalizeCustomers(runtime, input, config) {
78
+ const customers = input.customers.map((customer) => ({
79
+ ...customer,
80
+ name: config.trimNames ? customer.name.trim() : customer.name,
81
+ }));
82
+ return { customers };
83
+ }
84
+
85
+ export async function auditCustomers(runtime, input, config) {
86
+ await runtime.callEffect('audit.customers', input.customers, config);
87
+ }
88
+ ```
89
+
90
+ - `config` 来自节点 `{ config = { ... } }`,缺省 `{}`;结构字段 `inputs`、`outputs`、`waitFor`、`type`、`src`、`impl` 不进入 config。
91
+ - TransformNode 必须返回普通 object,own keys 与 outputs 完全一致。缺 key、多 key、返回非 object 都是协议 fault。
92
+ - SinkNode 必须返回 `undefined`/`void`;它没有可引用 port,但成功后可由 `flow-node://` 等待。
93
+ - `type` 是可选函数类型 export;`src` 或 `impl` 是 node-local implementation export。canonical node 至多声明一个 `src`/`impl`,Split/Public 装配也必须最终解析到唯一实现。
94
+ - code ref 只保存于 XNL;loader/compiler 不 import 或执行代码,materialization/runtime 才解析实现。
95
+
96
+ EntryNode、ReturnNode 和 SubFlowNode 是结构节点,不接受 `type`、`src` 或 `impl`。SubFlowNode 的代码边界由目标 FlowContract 定义。
97
+
98
+ ## SubFlowNode
99
+
100
+ ```xnl
101
+ <SubFlowNode #classify {
102
+ flow = "eager-data-flow://depa.flows.demo.CustomerClassification"
103
+ inputs = { customers = "flow-port://#normalize/customers" }
104
+ }>
105
+ ```
106
+
107
+ 链接期必须解析目标 EagerDataFlow 的 FlowContract。调用节点 inputs key 与目标 inputPorts 做集合相等校验;调用节点 outputs 不在本地声明,而是复制目标 outputPorts。子 flow 使用独立 invocation runtime state,父子之间只传 contract records。
108
+
109
+ 父流只观察 SubFlowNode 整体完成:子流内部 port 和 completion fact 都不可寻址。子流 fault 归一化为带父节点 id、目标 flow FQN 和原始 cause 的 SubFlow fault。
110
+
111
+ ## Ready scheduling
112
+
113
+ 调度器从两类依赖建立同一张联合 DAG,但在 authoring plan 中继续分别保存 dataEdges 和 waitForEdges:
114
+
115
+ ```text
116
+ ready(node) = every declared input port is published
117
+ && every waitFor target completed successfully
118
+ ```
119
+
120
+ 1. invocation input 通过 contract 校验后,EntryNode 发布 input ports。
121
+ 2. 每次 port 发布或节点完成后,调度器重新计算 ready set。
122
+ 3. 同一轮所有 ready 节点都可启动;不得按根数组顺序串行化。
123
+ 4. 节点启动后至多执行一次;output record 完整校验后原子发布全部 ports,再发布成功 completion fact。
124
+ 5. ReturnNode 捕获 output record;所有 definition nodes 均成功完成后 invocation 才成功返回。
125
+
126
+ 并发节点之间没有隐式 side-effect 顺序。若业务要求 `audit` 完成后才能 `archive`,必须像完整示例一样写 `waitFor`。重复声明相同 data/completion endpoint 可以同时存在,因为两类边保留不同 authoring intent。
127
+
128
+ ## 拓扑与链接校验
129
+
130
+ 加载/链接在执行任何代码前必须拒绝:
131
+
132
+ - 不是恰好一个 FlowContract、EntryNode 或 ReturnNode;
133
+ - 重复 node id、重复 port、未知节点或未知 output port;
134
+ - EntryNode 有 incoming dependency,ReturnNode 有 outgoing data edge,或节点依赖自身;
135
+ - dataEdges 与 waitForEdges 的并集存在直接或间接环;
136
+ - 存在无法从 EntryNode 经联合边到达的节点;
137
+ - ReturnNode inputs 与当前 outputPorts 不完全相等;
138
+ - SubFlowNode inputs/outputs 与目标 contract 不匹配,目标未注册或不是 EagerDataFlow;
139
+ - unit 级 SubFlowNode 调用图存在直接或间接递归。
140
+
141
+ 联合 DAG 校验使用 node identity;同一 endpoint 上同时存在 data edge 和 completion edge 时,拓扑算法可把它们视为一条邻接关系计算入度,但 authoring plan 和诊断必须保留两条原始事实。
142
+
143
+ ## 错误传播
144
+
145
+ 任一节点产生技术 fault 时,invocation 立即进入 failing:不再启动未开始节点,所有依赖该节点的节点保持未执行,已运行节点收到 runtime cancellation。并发中的其他 fault 可作为 causes 聚合;primary fault 必须按稳定拓扑层和根声明顺序选择,避免调度时序改变外部错误。
146
+
147
+ 失败 invocation 不返回 ReturnNode 捕获的部分 output。已经完成的 SinkNode 或其他 effect 不自动补偿;补偿、幂等和事务能力由显式 runtime/effect 契约提供。业务拒绝、空结果等仍是 port data,只有 throw、fault 或协议违反进入失败通道。
148
+
149
+ ## Rejected nodes
150
+
151
+ `ComputedNode`、`ProcessorNode`、`AsyncNode`、`ConsumerNode` 和 SignalNode 属于 lazy DataGraph。`ComputeNode`、`ConsumeNode` 也不是 EagerDataFlow alias。旧 `<DataFlow>` 根无效,即使内部节点全部符合本页也必须拒绝。
@@ -0,0 +1,90 @@
1
+ # L3 · EagerDataFlow 引用协议
2
+
3
+ > EagerDataFlow 同时使用 unit 引用、当前 flow 私有 node/port 引用和代码引用。scheme 决定 target 类别,不能仅凭字符串形状猜测。
4
+
5
+ ## 引用一览
6
+
7
+ | scheme | target | public fields | example |
8
+ |---|---|---|---|
9
+ | `eager-data-flow://` | 已注册的 EagerDataFlow FQN | `SubFlowNode.flow` | `"eager-data-flow://depa.flows.demo.Normalize"` |
10
+ | `flow-port://` | 当前 flow 某节点已声明的 output port | node `inputs` values | `"flow-port://#normalize/customers"` |
11
+ | `flow-node://` | 当前 flow 某节点的成功 completion fact | node `waitFor` items | `"flow-node://#audit"` |
12
+ | `vfs://` | type 或 implementation export | FlowContract `input`/`output`; node `type`/`src`/`impl` | `"vfs://./flow-code/export.ts#createArchive"` |
13
+ | `config://` | 当前 bundle ConfigEntry 或 sub-path | node config binding | `"config://#export/archiveFormat"` |
14
+ | `config-def://` | 当前 bundle ConfigEntryDef | config tooling | `"config-def://#export"` |
15
+ | `flow-authoring://` | 当前 bundle layout entry | editor projection | `"flow-authoring://#normalize"` |
16
+
17
+ `eager-data-flow://` 只解析公开根为 `EagerDataFlow` 的 unit;目标使用其他 root tag 时链接失败。
18
+
19
+ ## Data edge
20
+
21
+ 格式严格为:
22
+
23
+ ```text
24
+ flow-port://#<node-id>/<output-port>
25
+ ```
26
+
27
+ 它只能出现在 `inputs` map 的 value。`node-id` 和 `output-port` 都在当前 EagerDataFlow 内解析;目标节点必须存在并声明该 port。EntryNode ports 来自当前 FlowContract,TransformNode ports 来自 outputs,SubFlowNode ports 来自目标 FlowContract。
28
+
29
+ ```xnl
30
+ <TransformNode #flatten {
31
+ inputs = {
32
+ records = "flow-port://#subflow/records"
33
+ schema = "flow-port://#load-schema/schema"
34
+ }
35
+ outputs = ["archive"]
36
+ src = "vfs://./flow-code/export.ts#flatten"
37
+ }>
38
+ ```
39
+
40
+ ## Completion edge
41
+
42
+ 格式严格为:
43
+
44
+ ```text
45
+ flow-node://#<node-id>
46
+ ```
47
+
48
+ 它只能出现在 `waitFor` list。引用表示目标节点必须成功完成,不携带数据,也不能包含 `/port` sub-path。SinkNode 虽无 output port,仍可通过 completion fact 建立副作用顺序。
49
+
50
+ ```xnl
51
+ <SinkNode #publish {
52
+ inputs = { archive = "flow-port://#archive/archive" }
53
+ waitFor = ["flow-node://#audit"]
54
+ src = "vfs://./flow-code/export.ts#publish"
55
+ }>
56
+ ```
57
+
58
+ data edge 与 completion edge 即使 endpoint 相同也都保留。ready 条件要求两者分别满足;联合拓扑校验必须覆盖两者。
59
+
60
+ ## Subflow reference
61
+
62
+ ```xnl
63
+ <SubFlowNode #normalize {
64
+ flow = "eager-data-flow://depa.flows.demo.NormalizeCustomers"
65
+ inputs = { customers = "flow-port://#entry/customers" }
66
+ }>
67
+ ```
68
+
69
+ `eager-data-flow://<FQN>` 跨 unit 解析,但不能穿透目标内部。链接器读取目标 FlowContract 来校验 inputs 并派生 outputs;父 flow 后续只能引用 `flow-port://#normalize/<target-output-port>` 或 `flow-node://#normalize`。
70
+
71
+ Subflow unit 调用图必须无环。直接自调用或 A -> B -> A 都是链接错误,而不是 runtime recursion。
72
+
73
+ ## Code ref
74
+
75
+ `type`、`src`、`impl` 以及 FlowContract type 都使用带 export fragment 的 `vfs://<path>#<Export>`。只指向文件、使用非 vfs scheme、或在 XNL 中内嵌函数均无效。
76
+
77
+ - `./` 相对当前 flow bundle 根,`@/` 相对工作区根。
78
+ - `type` 指向函数/record type export,不执行。
79
+ - `src` / `impl` 指向动态实现 export;canonical node 至多声明其中一个。
80
+ - loader/compiler 只校验和投影引用,runtime materialization 才解析 module。
81
+
82
+ 动态实现统一遵守 `output = fn(runtime, input, config)`,详细 output 约束见[nodes](nodes.md#transformnode--sinknode-代码协议)。
83
+
84
+ ## 解析拒绝
85
+
86
+ - `flow-port://` / `flow-node://` 跨 unit、缺少 `#id` 或使用错误 sub-path。
87
+ - `waitFor` 使用 port ref,或 `inputs` 使用 node completion ref。
88
+ - SubFlowNode 指向旧 DataFlow 根、CtrlFlow profile 或未注册 FQN。
89
+ - 任何 URI 指向不存在的 node、port、entry、file 或 export。
90
+ - 使用 DataGraph 的 slot refs、`data-graph://` 或 `scope-data-graph://` 代替 flow dependency。
@@ -0,0 +1,39 @@
1
+ # L3 · flow-core 事实与域
2
+
3
+ > CtrlFlow statements 直接属于产品 definition,不是一个独立文件域。domain/file/root tag 与 entry scheme 按 M-N2 分投影,所有 scheme 必须在本页或 profile 规范中显式登记。
4
+
5
+ ## Authoring Facts
6
+
7
+ | owner | file / projection | root | entries | entry scheme | 语义 |
8
+ |---|---|---|---|---|---|
9
+ | flow definition | 单文件或 `manifest.xnl` | `InstantCtrlFlow` / `WorkCtrlFlow` / `BPCtrlFlow` | 根 `[]` 中的 statements | 无 | 唯一 topology 与 node config 真源 |
10
+ | flow contract | 根 `()` 内联或 `flow.contract.xnl` | `FlowContract` | 无 | 产品 flow scheme | 静态 input/output 类型与可调用边界 |
11
+ | `config` | `config.xnl` | `Config` | `ConfigEntry` | `config://` | 静态开关、枚举、常量预设 |
12
+ | `config.def` | `config.def.xnl` | `ConfigDef` | `ConfigEntryDef` | `config-def://` | config shape facet |
13
+ | `flow.authoring` | `flow.authoring.xnl` | `FlowAuthoring` | `NodeLayout` | `flow-authoring://` | layout/viewport;不得复制语义定义 |
14
+
15
+ CtrlFlow 只命名共享 statement grammar、canonical AST 和 editor adapter,不形成可独立加载的 definition unit。
16
+
17
+ ## Derived And Runtime Facts
18
+
19
+ | fact | owner | persistence rule |
20
+ |---|---|---|
21
+ | canonical FlowSpec / CtrlFlow AST | parser/compiler | 可从 XNL definition 重建;不是第二份 authoring 文件 |
22
+ | BehaviorTreePlan | compiler | 内部派生执行计划;不得被 loader 当作公开 definition |
23
+ | WorkCtrlFlow snapshot | WorkCtrlFlow/BPCtrlFlow runtime | 运行实例状态;不得回写 definition |
24
+ | TaskSpace facts | BPCtrlFlow task store | 人工任务事实源;结果以 data 进入 flow |
25
+ | runtime overlay | editor/runtime adapter | 只读投影;不得覆盖 definition 或 FlowAuthoring |
26
+
27
+ ## Loader Validation
28
+
29
+ 1. definition 根 tag 必须是公开产品根,`#id` 必须是 FQN;`apiVersion` / `version` 必须位于 metadata 段。
30
+ 2. 根 `[]` 直接包含 profile 允许的 statements;根包装或第二份 topology 是错误。
31
+ 3. 每个 definition 恰有一个 `FlowContract`,且其 `#id` 等于根 FQN。
32
+ 4. statement `#id` 在 definition 内唯一;`If` 恰有一个 `Branches` 子域,`Otherwise` 最多一个且必须末尾。
33
+ 5. 所有 code ref 必须是带 export fragment 的 `vfs://...#Export`;XNL 中的函数或表达式字符串是错误。
34
+ 6. `config://` 与 `config-def://` 只在当前 bundle 内解析,目标 entry 必须存在。
35
+ 7. profile capability 由[编排原语与产品能力](orchestration.md)收窄;grammar 合法不代表当前 runtime 已实现。
36
+
37
+ ## Rejected Public Domains
38
+
39
+ 旧结构根、公开行为树控制节点和动作类型目录不属于 authoring domain。实现若需要行为树节点种类,只能在编译出的内部 BehaviorTreePlan 中表达。
@@ -0,0 +1,50 @@
1
+ # L3 · flow-core 文件组织
2
+
3
+ ## 单文件 bundle
4
+
5
+ 小型 flow 可以由一个 XNL 文件承载完整 definition;文件名只参与布局,根 tag 与 `#id` 才决定产品类别和身份。
6
+
7
+ ```text
8
+ flows/
9
+ price-quote.xnl # <InstantCtrlFlow #depa.flows.demo.PriceQuote [...]>
10
+ flow-code/
11
+ quote.ts
12
+ ```
13
+
14
+ 产品根的 `[]` 直接保存 CtrlFlow statements。唯一子域才进入 `()`;不得用额外根节点包装 statements。
15
+
16
+ ## 目录 bundle
17
+
18
+ 复杂 flow 使用目录 unit:
19
+
20
+ ```text
21
+ flows/order-routing/
22
+ manifest.xnl # <WorkCtrlFlow #depa.flows.demo.OrderRouting [...]>
23
+ flow.contract.xnl # 可选外提;逻辑上仍是必需且唯一的 FlowContract
24
+ config.xnl # 可选静态 config 域
25
+ config.def.xnl # 可选 config shape facet
26
+ flow.authoring.xnl # 可选布局事实,不复制 statements
27
+ flow-code/
28
+ order.types.ts
29
+ order.ts
30
+ ```
31
+
32
+ profile 可以增加自己的状态或任务文件,见对应 `spec/<profile>/domains.md`。公共语言不通过独立结构文件或类型目录定义 statements;节点 tag、字段和就地 code ref 已经构成完整 authoring 事实。
33
+
34
+ ## 单/多文件边界
35
+
36
+ - `manifest.xnl` 是目录 bundle 的唯一入口;根 tag ∈ {`InstantCtrlFlow`, `WorkCtrlFlow`, `BPCtrlFlow`}。
37
+ - 根 `[]` 的 statement topology 始终由入口 definition 持有。
38
+ - 每个 definition 必须恰有一个 `FlowContract`;可内联,也可外提为 `flow.contract.xnl`,不能两处同时声明。
39
+ - 根 `()` 中的唯一子域可以按 M-S4 外提为同型域文件;外提不改变逻辑 URI。
40
+ - `vfs://./...` 相对 bundle 根解析,单文件和目录形态保持一致。
41
+ - code export 只存在于 `.ts` 等脚本文件;XNL 只保存 `vfs://...#Export` 引用。
42
+ - `flow.authoring.xnl` 只保存 layout/viewport,不得复制 statement topology、node config 或运行状态。
43
+
44
+ ## Removed File Shapes
45
+
46
+ 以下旧文件形态是校验错误,不是兼容入口:
47
+
48
+ - `tree.xnl` 或内联 `Tree` 结构域。
49
+ - `action.types.xnl` 或内联 `ActionTypes` 类型目录。
50
+ - 以独立可执行 `CtrlFlow` 根保存三种产品共有语句。