{
  "name": "Orchestrator: Loop call-workflow over KG",
  "goal": "Read rows from a KG list, call a child workflow per row to score/process each, persist the results back to KG, then summarize.",
  "description": "Pattern 11 (orchestrator) wired to a child built from the `child-with-return` scaffold. The KG list is the source of truth; the child encapsulates the per-row logic. Uses `entryConditions.type: \"loop_completion\"` with `onCriteriaFail: \"wait\"` so downstream steps block until every child finishes.",
  "status": "draft",
  "context": {
    "executionInputConfig": {
      "title": "Orchestrate Scoring",
      "description": "Score every `new` row in the KG list by calling a child workflow per row.",
      "runCTALabel": "Run",
      "allowRegeneration": false,
      "fields": [
        { "name": "source_list_key", "label": "Source KG list key", "type": "text", "required": true },
        { "name": "child_workflow_id", "label": "Child workflow id (the scoring workflow)", "type": "text", "required": true }
      ]
    }
  },
  "steps": [
    {
      "id": "start",
      "type": "trigger",
      "name": "Manual Start",
      "pipelineStepStartConditions": { "trigger": { "type": "manual" } },
      "next": { "stepId": "read-candidates" }
    },
    {
      "id": "read-candidates",
      "type": "appAction",
      "name": "Read Candidates from KG",
      "app": { "id": "kg", "actionId": "kg.read-list", "source": "native" },
      "stepInputData": {
        "listKey": "{{input.source_list_key}}",
        "status": "new",
        "limit": "50"
      },
      "next": { "stepId": "call-child" }
    },
    {
      "id": "call-child",
      "type": "appAction",
      "name": "Score Row (child workflow)",
      "loopConfig": {
        "source": "executionContent",
        "config": { "stepId": "read-candidates", "field": "listEntries" },
        "ItemAlias": "row"
      },
      "app": { "id": "agentled", "actionId": "agentled.call-workflow", "source": "native" },
      "stepInputData": {
        "workflowId": "{{input.child_workflow_id}}",
        "executionInputData": "{\"entity_id\": \"{{row.id}}\", \"entity_url\": \"{{row.url}}\"}",
        "timeoutMinutes": "30"
      },
      "next": { "stepId": "persist-scores" }
    },
    {
      "id": "persist-scores",
      "type": "appAction",
      "name": "Write Scores Back to KG",
      "app": { "id": "kg", "actionId": "kg.update-rows", "source": "native" },
      "entryConditions": {
        "onCriteriaFail": "wait",
        "conditionText": "Wait for every child call to complete before flipping status.",
        "criteria": [
          { "type": "loop_completion", "stepId": "call-child", "operator": "==", "value": true }
        ]
      },
      "stepInputData": {
        "listKey": "{{input.source_list_key}}",
        "rowIds": "{{steps.call-child.rowIds}}",
        "fieldUpdates": "{{steps.call-child.returnData}}",
        "status": "scored"
      },
      "next": { "stepId": "summarize" }
    },
    {
      "id": "summarize",
      "type": "aiAction",
      "name": "Summarize Run",
      "pipelineStepPrompt": {
        "template": "Summarize this orchestration run.\n\nRows processed: {{steps.read-candidates.count}}\nResults: {{steps.call-child.returnData}}\n\nReport totals, top-3 by score, and anything that looked anomalous.",
        "responseStructure": {
          "totals": "object — counts by decision bucket",
          "top": "array — top 3 rows",
          "notes": "string"
        }
      },
      "creditCost": 5,
      "next": { "stepId": "done" }
    },
    {
      "id": "done",
      "type": "milestone",
      "name": "Orchestration Done"
    }
  ]
}
