{
  "name": "CWF-110 Topic Discovery Canonical",
  "description": "Canonical executable topic discovery workflow.",
  "nodes": [
    {
      "parameters": {},
      "id": "cwf-110_trigger_node",
      "name": "Trigger Node",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1,
      "position": [
        200,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "return [{ json: { ...$json, dossier_context: { dossier_id: $json.dossier_id || 'DOSSIER-UNSPECIFIED', loaded_at: new Date().toISOString() } } }];"
      },
      "id": "cwf-110_dossier_load_node",
      "name": "Dossier Load Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        420,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "return [{ json: { ...$json, registry_lookup: { skill_registry: 'registries/skill_registry.yaml', workflow_bindings: 'registries/workflow_bindings.yaml', schema_registry: 'registries/schema_registry.yaml', director_binding: 'registries/director_binding.yaml' } } }];"
      },
      "id": "cwf-110_registry_lookup_node",
      "name": "Registry Lookup Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        640,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "try {\n  const SkillLoader = require('../../../engine/skill_loader/skill_loader.js');\n  const loader = new SkillLoader();\n\n  // Initialize loader if not already done\n  if (!loader.skills_registry || Object.keys(loader.skills_registry).length === 0) {\n    const initResult = await loader.initialize();\n    if (initResult.status !== 'initialized') {\n      throw new Error('Failed to initialize SkillLoader');\n    }\n  }\n\n  // Get skill_id from input or workflow context\n  const skillId = $json.skill_id || 'M-001';\n  const dossierId = $json.dossier_context?.dossier_id || $json.dossier_id || 'DOSSIER-UNSPECIFIED';\n\n  // Build context packet\n  const contextPacket = {\n    dossier_id: dossierId,\n    ...(typeof $json.user_context === 'object' ? $json.user_context : {}),\n    ...(typeof $json.route_context === 'object' ? $json.route_context : {})\n  };\n\n  // Build dossier state\n  const dossierState = typeof $json.dossier === 'object' ? $json.dossier : {};\n\n  // Execute skill\n  const result = await loader.executeSkill(skillId, contextPacket, dossierState);\n\n  // Return result\n  if (result.status === 'SUCCESS') {\n    return [{\n      json: {\n        ...$json,\n        runtime_packet: result.output,\n        skill_execution_result: result,\n        runtime: { had_error: false, error_message: '' }\n      }\n    }];\n  } else {\n    throw new Error(`Skill execution failed: ${result.error}`);\n  }\n} catch (error) {\n  // Strict mode: never synthesize runtime packets in production path\n  const message = String(error && error.message ? error.message : error);\n  return [{\n    json: {\n      ...$json,\n      runtime_packet: null,\n      skill_execution_result: null,\n      runtime: { had_error: true, error_message: message }\n    }\n  }];\n}"
      },
      "id": "cwf-110_skill_execution_node",
      "name": "Skill Execution Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        860,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "try {\n  const packet = $json.runtime_packet;\n  if (!packet || !packet.instance_id || !packet.artifact_family || !packet.dossier_ref) {\n    throw new Error('missing required runtime_packet fields');\n  }\n  return [{ json: { ...$json, validation_status: 'SUCCESS', route_to_error: false } }];\n} catch (error) {\n  return [{ json: { ...$json, validation_status: 'FAILED', route_to_error: true, validation_error: String(error.message || error) } }];\n}"
      },
      "id": "cwf-110_packet_validation_node",
      "name": "Packet Validation Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1080,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "if ($json.route_to_error) return [];\nreturn [{\n  json: {\n    ...$json,\n    dossier_write: {\n      mutation_type: 'append_to_array',\n      target: 'dossier.runtime_packets',\n      timestamp: new Date().toISOString(),\n      writer_id: 'CWF-110',\n      skill_id: 'CWF-110',\n      instance_id: $json.runtime_packet.instance_id,\n      schema_version: $json.runtime_packet.schema_version,\n      lineage_reference: $json.runtime_packet.producer_workflow,\n      audit_entry: 'append-only dossier write from canonical workflow'\n    }\n  }\n}];"
      },
      "id": "cwf-110_append_only_dossier_write_node",
      "name": "Append-Only Dossier Write Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1300,
        220
      ]
    },
    {
      "parameters": {
        "jsCode": "if ($json.route_to_error) return [];\nreturn [{\n  json: {\n    ...$json,\n    se_packet_index_write: {\n      operation: 'create_new_index_row',\n      packet_id: $json.runtime_packet.instance_id,\n      dossier_id: $json.runtime_packet.dossier_ref,\n      packet_family: $json.runtime_packet.artifact_family,\n      workflow_id: 'CWF-110',\n      created_at: new Date().toISOString()\n    }\n  }\n}];"
      },
      "id": "cwf-110_packet_index_write_node",
      "name": "se_packet_index Write Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1520,
        220
      ]
    },
    {
      "parameters": {
        "jsCode": "if (!$json.route_to_error) return [];\nreturn [{\n  json: {\n    workflow_id: 'CWF-110',\n    routing_decision: 'ERROR',\n    route_to_workflow: 'WF-900',\n    error_message: $json.validation_error || $json.runtime?.error_message || 'unknown workflow error',\n    failure_packet: $json.runtime_packet || null\n  }\n}];"
      },
      "id": "cwf-110_wf900_error_routing_node",
      "name": "Error Routing WF-900 Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1300,
        420
      ]
    },
    {
      "parameters": {
        "jsCode": "if ($json.route_to_error) return [];\nlet nextWorkflow = 'CWF-120';\nlet decision = 'SUCCESS_PATH';\n\nif ('CWF-110' === 'CWF-140') {\n  const confidence = Number($json.runtime_packet?.payload?.research_confidence_score ?? 1);\n  if (confidence < 0.85) {\n    nextWorkflow = 'CWF-140';\n    decision = 'RUN_PHASE1C_CONDITIONAL_RESEARCH';\n  } else {\n    nextWorkflow = 'CWF-210';\n    decision = 'SKIP_PHASE1C_PROCEED_SCRIPT';\n  }\n}\n\nif ('CWF-110' === 'WF-020') {\n  const approval = String($json.runtime_packet?.payload?.approval_decision || 'APPROVED');\n  nextWorkflow = approval === 'APPROVED' ? 'WF-300' : 'WF-021';\n  decision = approval === 'APPROVED' ? 'APPROVED_FOR_PUBLISHING' : 'REJECTED_ROUTE_REPLAY';\n}\n\nif ('CWF-110' === 'WF-021') {\n  nextWorkflow = $json.replay_target_workflow || 'CWF-210';\n  decision = 'REPLAY_TO_PRIOR_STAGE';\n}\n\nreturn [{\n  json: {\n    ...$json,\n    routing_decision: {\n      on_success_next_workflow: nextWorkflow,\n      on_error_workflow: 'WF-900',\n      decision,\n      wf900_bound: true\n    }\n  }\n}];"
      },
      "id": "cwf-110_next_stage_routing_node",
      "name": "Next-Stage Routing Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1740,
        220
      ]
    },
    {
      "parameters": {
        "jsCode": "if ($json.route_to_error) return [];\nreturn [{\n  json: {\n    workflow_id: 'CWF-110',\n    execution_status: 'SUCCESS',\n    completion_packet: {\n      instance_id: 'CWF-110-COMP-' + Date.now(),\n      artifact_family: 'workflow_completion_packet',\n      schema_version: '1.0.0',\n      producer_workflow: 'CWF-110',\n      dossier_ref: $json.runtime_packet?.dossier_ref || 'DOSSIER-UNSPECIFIED',\n      created_at: new Date().toISOString(),\n      status: 'CREATED',\n      payload: {\n        source_packet_id: $json.runtime_packet?.instance_id || null,\n        next_workflow: $json.routing_decision?.on_success_next_workflow || 'CWF-120',\n        route_to_wf900: 'WF-900'\n      }\n    }\n  }\n}];"
      },
      "id": "cwf-110_completion_packet_emission_node",
      "name": "Completion Packet Emission Node",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1960,
        220
      ]
    }
  ],
  "connections": {
    "Trigger Node": {
      "main": [
        [
          {
            "node": "Dossier Load Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Dossier Load Node": {
      "main": [
        [
          {
            "node": "Registry Lookup Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Registry Lookup Node": {
      "main": [
        [
          {
            "node": "Skill Execution Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skill Execution Node": {
      "main": [
        [
          {
            "node": "Packet Validation Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Packet Validation Node": {
      "main": [
        [
          {
            "node": "Append-Only Dossier Write Node",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Routing WF-900 Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append-Only Dossier Write Node": {
      "main": [
        [
          {
            "node": "se_packet_index Write Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "se_packet_index Write Node": {
      "main": [
        [
          {
            "node": "Next-Stage Routing Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Next-Stage Routing Node": {
      "main": [
        [
          {
            "node": "Completion Packet Emission Node",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "workflow_id": "CWF-110",
    "phase": "phase1",
    "vein": "discovery_vein",
    "purpose": "Discover and package candidate topics with deterministic governance controls.",
    "implementation_depth": "production_grade",
    "owner_director": "Narada",
    "next_workflow": "CWF-120",
    "canonical_file": "n8n/workflows/CWF-110.json",
    "legacy_file": "n8n/workflows/topic/CWF-110-topic-discovery.json",
    "required_node_contract": [
      "trigger_node",
      "dossier_load_node",
      "registry_lookup_node",
      "skill_execution_node",
      "packet_validation_node",
      "append_only_dossier_write_node",
      "packet_index_write_node",
      "wf900_error_routing_node",
      "next_stage_routing_node",
      "completion_packet_emission_node"
    ],
    "wf900_error_route": "WF-900"
  },
  "active": true,
  "settings": {}
}