{ "id": "executor-fanout", "label": "执行型 org node 的 work graph(fan-out / fan-in 起手式)", "whenToUse": "宿主 org node 是执行类,且这次任务能拆成多个互不依赖、可并行推进的分支时用本骨架——27-REQ R-6 第 6 步描述的就是它:拆分 → 并行实现 + 各自自测(自测失败只回退本分支)→ fan-in 汇合整合 → 集成测试 → 本层验收。典型信号词:多个模块、多个页面、多个接口、可以同时做。汇合节点有多条入边,引擎按「全部入边条件都满足才置 ready」处理(27-P3/P4 §四.D.1)。分支数按实际任务增减,本文件给的是 2 条;任务只有一个交付物就别用它,用 executor.json。", "ownerOrgNode": "{{orgNode}}", "dataContractNotes": "拆分节点的产物声明成 contract(分支间接口契约)而不是 artifact:两条分支各自的交付物已经占了 artifact 这个 kind,而产物索引按 task + kind 查、同一 kind 只把最新那份递给下游,拆分方案写成 artifact 会被先跑完的分支产物顶掉。代价是 contract 属任务级共享 kind,本来就会自动递给每个节点,所以这两条声明的实际作用偏诊断(声明了却查不到实例时,提示词会显式标 ⚠️,等于当场暴露「拆分节点没产出接口契约」)。fan-in 的已知上限:merge 的两条入边各自 needs artifact,但索引按 kind 只回最新一份,merge 提示词里只会出现一条路径——两个分支的产物都要过目时,merge 仍得按提示词给的节点目录自己找齐。升级路径是让产物索引支持按 fromNodeId 过滤(inboundContracts 已经带回 fromNodeId,describeInputs 还没用它)。", "nodes": [ { "nodeName": "{{orgNode}}-split", "systemAgentId": "{{splitAgent}}" }, { "nodeName": "{{orgNode}}-impl-a", "systemAgentId": "{{implAgent}}" }, { "nodeName": "{{orgNode}}-impl-b", "systemAgentId": "{{implAgent}}" }, { "nodeName": "{{orgNode}}-test-a", "systemAgentId": "{{testAgent}}" }, { "nodeName": "{{orgNode}}-test-b", "systemAgentId": "{{testAgent}}" }, { "nodeName": "{{orgNode}}-merge", "systemAgentId": "{{mergeAgent}}" }, { "nodeName": "{{orgNode}}-integration", "systemAgentId": "{{integrationAgent}}" }, { "nodeName": "{{orgNode}}-validator", "systemAgentId": "{{validatorAgent}}" } ], "edges": [ { "from": "{{orgNode}}-split", "to": "{{orgNode}}-impl-a", "condition": "success", "produces": ["contract"] }, { "from": "{{orgNode}}-split", "to": "{{orgNode}}-impl-b", "condition": "success", "produces": ["contract"] }, { "from": "{{orgNode}}-impl-a", "to": "{{orgNode}}-test-a", "condition": "success", "produces": ["artifact"] }, { "from": "{{orgNode}}-impl-b", "to": "{{orgNode}}-test-b", "condition": "success", "produces": ["artifact"] }, { "from": "{{orgNode}}-test-a", "to": "{{orgNode}}-merge", "condition": "success", "produces": ["log"], "needs": ["artifact"] }, { "from": "{{orgNode}}-test-b", "to": "{{orgNode}}-merge", "condition": "success", "produces": ["log"], "needs": ["artifact"] }, { "from": "{{orgNode}}-merge", "to": "{{orgNode}}-integration", "condition": "success", "produces": ["artifact"] }, { "from": "{{orgNode}}-integration", "to": "{{orgNode}}-validator", "condition": "success", "produces": ["log"], "needs": ["artifact"] }, { "from": "{{orgNode}}-test-a", "to": "{{orgNode}}-impl-a", "condition": "fail", "edgeKind": "backward" }, { "from": "{{orgNode}}-test-b", "to": "{{orgNode}}-impl-b", "condition": "fail", "edgeKind": "backward" }, { "from": "{{orgNode}}-integration", "to": "{{orgNode}}-merge", "condition": "fail", "edgeKind": "backward" }, { "from": "{{orgNode}}-validator", "to": "{{orgNode}}-split", "condition": "fail", "edgeKind": "backward" } ] }