meta:
  name: node_state_machine
  version: 0.1
  language: zh-CN
  desc: "节点状态机配置（用于驱动/校验未来的状态机组件）"

  # 命名约定（配置内唯一真名；图上不再有 display/别名）：
  # - Sxx: State / PseudoState（节点）
  # - Exx: Event（事件）
  # - 事件分支由渲染器在边上追加 a/b/c...（对应 outcomes 顺序）
  id_convention:
    state_prefix: "S"
    event_prefix: "E"

# Variables are computed by the caller and passed into the state machine.
# Rule: the YAML never directly mutates "peer" nodes. Cross-node changes must be
# represented as separate invocations with different inputs.
context:
  is_create_zombie: { type: bool, desc: "初始化时判定为 CREATE 僵尸：action=CREATE 且 (status=FAILED 或 data_id 为空)" }

  has_binding_record: { type: bool, desc: "binding_manager 里存在绑定记录 (remote_id/local_id 非空)" }
  core_binding_result: { type: enum, values: [NORMAL, WARNING, ABNORMAL], desc: "SyncDecisionEngine.determine_core_status() 给本节点的结果（仅在 has_binding_record=true 时有效）" }
  peer_core_binding_result: { type: enum, values: [NORMAL, WARNING, ABNORMAL], desc: "SyncDecisionEngine.determine_core_status() 给对方节点的结果（用于静态约束 core matrix 对称性）" }

  data_present: { type: bool, desc: "node.get_data() 非空" }
  has_depend_fields: { type: bool, desc: "config.depend_fields 非空" }
  dep_satisfied: { type: bool, desc: "依赖满足：空依赖值跳过；非空依赖值必须能在 collection 中按 data_id 找到且节点状态可用" }

  auto_bind_enabled: { type: bool, desc: "config.auto_bind && auto_bind_fields 非空" }
  auto_bind_outcome:
    type: enum
    values: [ONE_TO_ONE, AMBIGUOUS, ZERO, KEY_MISSING, KEY_ID_RESOLVE_FAIL, DATA_MISSING]
    desc: "自动绑定结果（由业务代码完成全集搜索+去噪后 1:1 判定）"

  create_enabled: { type: bool, desc: "create() 是否对当前方向启用 (local_orphan_action/remote_orphan_action)" }
  create_id_resolve_ok: { type: bool, desc: "IDResolver.resolve_and_validate() 是否成功" }
  spawn_success: { type: bool, desc: "创建副作用（spawn + bind）是否成功" }

  update_enabled: { type: bool, desc: "update() 是否启用 (update_direction != NONE)" }
  target_has_data_id: { type: bool, desc: "UPDATE 目标节点 data_id 非空" }
  update_id_resolve_ok: { type: bool, desc: "UPDATE 前 IDResolver.resolve_and_validate() 是否成功" }
  has_diff: { type: bool, desc: "needs_update_check 判定有差异" }

  handler_result:
    type: enum
    values: [SUCCESS, FAILED, SKIPPED, IN_PROGRESS]
    desc: "TaskResult.status"
  poll_timeout: { type: bool, desc: "异步轮询超过 max_retries" }
  execute_action:
    type: enum
    values: [CREATE, UPDATE, DELETE, NONE]
    desc: "E40 执行时的动作类型（用于区分 SKIPPED 的落点）"

# State IDs are for visualization and static validation.
# NOTE: 本状态机按“加载时清空执行状态，再开始本轮”建模：
# - 加载/初始化后，稳态节点的 status 统一回到 PENDING
# - 上一轮遗留的 FAILED/SUCCESS 等不作为本轮的入口状态
states:
  # --- Stable entry to bind (after init reset + zombie cleanup) ---
  S00:
    binding_status: UNCHECKED
    action: NONE
    status: PENDING
    data_id_exist: true
    desc: |
      进入 bind 前的唯一起点
      binding_status: UNCHECKED
      action: NONE
      status: PENDING
      data_id_exist: true

  # --- Bind results ---
  S01:
    binding_status: NORMAL
    action: NONE
    status: PENDING
    data_id_exist: true
    desc: |
      绑定正常（待后续 update 检查）
      binding_status: NORMAL
      action: NONE
      status: PENDING
      data_id_exist: true

  S02:
    binding_status: MISSING
    action: NONE
    status: PENDING
    data_id_exist: true
    desc: |
      孤儿节点（可能进入 create / auto_bind / delete）
      binding_status: MISSING
      action: NONE
      status: PENDING
      data_id_exist: true

  S03:
    binding_status: ABNORMAL
    action: NONE
    status: PENDING
    data_id_exist: true
    desc: |
      数据损坏/缺失（阻断态，需人工）
      binding_status: ABNORMAL
      action: NONE
      status: PENDING
      data_id_exist: true
  S04:
    binding_status: WARNING
    action: NONE
    status: PENDING
    data_id_exist: true
    desc: |
      不可自动处理（阻断态，需人工）
      binding_status: WARNING
      action: NONE
      status: PENDING
      data_id_exist: true
  S05:
    binding_status: DEPENDENCY_ERROR
    action: NONE
    status: PENDING
    data_id_exist: true
    desc: |
      依赖项不满足/ID解析失败（阻断态）
      binding_status: DEPENDENCY_ERROR
      action: NONE
      status: PENDING
      data_id_exist: true

  # --- Create & Update prepared actions (target-side nodes) ---
  S06:
    binding_status: NORMAL
    action: CREATE
    status: PENDING
    data_id_exist: false
    shape: pseudo
    desc: |
      待执行 CREATE（执行入口）
      binding_status: NORMAL
      action: CREATE
      status: PENDING
      data_id_exist: false
  S07:
    binding_status: NORMAL
    action: UPDATE
    status: PENDING
    data_id_exist: true
    desc: |
      准备更新
      binding_status: NORMAL
      action: UPDATE
      status: PENDING
      data_id_exist: true

  S08:
    binding_status: NORMAL
    action: UPDATE
    status: PRECONDITION_FAILED
    data_id_exist: [false, true]
    desc: |
      更新前置失败（缺 data_id / 依赖ID未解析等）
      binding_status: NORMAL
      action: UPDATE
      status: PRECONDITION_FAILED
      data_id_exist: false | true

  S09:
    binding_status: NORMAL
    action: DELETE
    status: PENDING
    data_id_exist: true
    desc: |
      待执行 DELETE（执行入口）
      binding_status: NORMAL
      action: DELETE
      status: PENDING
      data_id_exist: true

  # --- Sync results ---
  S10C:
    binding_status: NORMAL
    action: CREATE
    status: IN_PROGRESS
    data_id_exist: false
    desc: |
      CREATE 异步执行中
      binding_status: NORMAL
      action: CREATE
      status: IN_PROGRESS
      data_id_exist: false
  S10U:
    binding_status: NORMAL
    action: UPDATE
    status: IN_PROGRESS
    data_id_exist: true
    desc: |
      UPDATE 异步执行中
      binding_status: NORMAL
      action: UPDATE
      status: IN_PROGRESS
      data_id_exist: true
  S10D:
    binding_status: NORMAL
    action: DELETE
    status: IN_PROGRESS
    data_id_exist: true
    desc: |
      DELETE 异步执行中
      binding_status: NORMAL
      action: DELETE
      status: IN_PROGRESS
      data_id_exist: true
  S11C:
    binding_status: NORMAL
    action: CREATE
    status: SUCCESS
    data_id_exist: true
    desc: |
      CREATE 执行成功
      binding_status: NORMAL
      action: CREATE
      status: SUCCESS
      data_id_exist: true
  S11U:
    binding_status: NORMAL
    action: UPDATE
    status: SUCCESS
    data_id_exist: true
    desc: |
      UPDATE 执行成功
      binding_status: NORMAL
      action: UPDATE
      status: SUCCESS
      data_id_exist: true
  S11D:
    binding_status: NORMAL
    action: DELETE
    status: SUCCESS
    data_id_exist: true
    desc: |
      DELETE 执行成功（随后删除节点）
      binding_status: NORMAL
      action: DELETE
      status: SUCCESS
      data_id_exist: true
  S12C:
    binding_status: NORMAL
    action: CREATE
    status: FAILED
    data_id_exist: [false, true]
    desc: |
      CREATE 执行失败
      binding_status: NORMAL
      action: CREATE
      status: FAILED
      data_id_exist: false | true
  S12U:
    binding_status: NORMAL
    action: UPDATE
    status: FAILED
    data_id_exist: [false, true]
    desc: |
      UPDATE 执行失败
      binding_status: NORMAL
      action: UPDATE
      status: FAILED
      data_id_exist: false | true
  S12D:
    binding_status: NORMAL
    action: DELETE
    status: FAILED
    data_id_exist: [false, true]
    desc: |
      DELETE 执行失败
      binding_status: NORMAL
      action: DELETE
      status: FAILED
      data_id_exist: false | true

  S13:
    binding_status: PEER_CREATING
    action: NONE
    status: PENDING
    data_id_exist: true
    desc: |
      对侧创建进行中（本侧等待提交）
      binding_status: PEER_CREATING
      action: NONE
      status: PENDING
      data_id_exist: true

  # Handler 在 update 路径中可能把 action 降级为 NONE 并返回 SKIPPED。
  # NOTE: 这会产生 (NORMAL, NONE, SKIPPED)，并且该节点会被统计到 none 列。
  S14:
    binding_status: NORMAL
    action: NONE
    status: SKIPPED
    data_id_exist: true
    desc: |
      更新被跳过（执行时降级为 NONE）
      binding_status: NORMAL
      action: NONE
      status: SKIPPED
      data_id_exist: true

pseudo_states:
  S15:
    desc: "节点被清理删除（zombie cleanup）"
  S16:
    desc: "持久化加载输入态：本轮 E01 的输入节点集合（可包含上轮遗留与已稳定节点）"
  S17:
    desc: "加载异常隔离态：持久化枚举非法，保留错误供人工处理，不进入自动流程"

stages:
  bootstrap:
    desc: "启动/初始化（仅针对持久化加载出的节点）：僵尸清理与归并到 S00"
    entry_states: [S16]
    exit_states: [S00, S15]

  bind:
    desc: "绑定判定：core matrix +（可选）依赖检查 +（可选）自动绑定；stage 仅约束边界，不要求内部顺序"
    entry_states: [S00]
    exit_states: [S01, S02, S03, S04, S05, S13]

  create_prepare:
    desc: "Create: 从 MISSING 源节点发起创建请求并在副作用提交后归并"
    entry_states: [S02, S13]
    exit_states: [S01, S02, S04, S05, S09, S13]

  update_prepare:
    desc: "Update: 检测差异并在目标节点上设置 UPDATE/PRECONDITION_FAILED"
    entry_states: [S01]
    exit_states: [S01, S07, S08]

  post_create_ready:
    desc: "创建成功后归并：CREATE 成功节点回到 NORMAL/NONE/PENDING，作为 update 起点"
    entry_states: [S11C]
    exit_states: [S01]

  sync_execute:
    desc: "Sync: DataSource 调用 handler，根据 TaskResult 更新 status；部分 handler 可能降级 action"
    entry_states: [S06, S07, S09, S10C, S10U, S10D]
    exit_states: [S10C, S10U, S10D, S11C, S11U, S11D, S12C, S12U, S12D, S14]

transitions:
  E01:
    stage: bootstrap
    desc: "初始化：删CREATE僵尸；其余重置后进入起点"
    from: [S16]
    outcomes:
      - when: { is_create_zombie: true }
        to: S15
      - when: { is_create_zombie: false }
        to: S00

  # --- Bind phase1 core ---
  E10:
    stage: bind
    desc: "核心绑定判定：有绑定按core结果分流；无绑定→MISSING"
    from: [S00]
    outcomes:
      - when: { has_binding_record: true, core_binding_result: NORMAL, peer_core_binding_result: NORMAL }
        to: S01
        emit:
          note: "绑定关系一致，进入正常态"
      - when: { has_binding_record: true, core_binding_result: WARNING, peer_core_binding_result: ABNORMAL }
        to: S04
        emit:
          note: "对端异常，本端标记WARNING"
      - when: { has_binding_record: true, core_binding_result: ABNORMAL, peer_core_binding_result: WARNING }
        to: S03
        emit:
          note: "本端异常，进入ABNORMAL"
      - when: { has_binding_record: true, core_binding_result: ABNORMAL, peer_core_binding_result: ABNORMAL }
        to: S03
        emit:
          note: "双方异常，进入ABNORMAL"
      - when: { has_binding_record: false }
        to: S02
        emit:
          note: "无绑定记录，标记为MISSING"

  # --- Bind phase2 dependency ---
  E15:
    stage: bind
    desc: "依赖检查：失败→阻断；缺少依赖配置→WARNING；通过→不变（不在图上画自环）"
    from: [S02]
    outcomes:
      - when: { has_depend_fields: false, data_present: true }
        to: S04
        emit:
          note: "缺少依赖字段配置，无法自动处理"
      - when: { data_present: false }
        to: S03
        emit:
          note: "节点数据为空或不存在"
      - when: { data_present: true, has_depend_fields: true, dep_satisfied: false }
        to: S05
        emit:
          note: "依赖项不满足"

  # --- Bind phase3 auto bind ---
  E16:
    stage: bind
    desc: "自动绑定：1:1→NORMAL；歧义/缺字段/数据为空→阻断；N:0 且允许创建→S13 等待创建提交"
    from: [S02]
    outcomes:
      - when: { auto_bind_enabled: false }
        to: S04
        emit:
          note: "自动绑定未启用"
      - when: { auto_bind_enabled: true, auto_bind_outcome: DATA_MISSING }
        to: S04
        emit:
          note: "节点数据为空，无法自动绑定"
      - when: { auto_bind_enabled: true, auto_bind_outcome: ONE_TO_ONE }
        to: S01
        emit:
          note: "自动绑定成功（1:1）"
      - when: { auto_bind_enabled: true, auto_bind_outcome: AMBIGUOUS }
        to: S04
        emit:
          note: "存在多个候选节点，无法自动绑定"
      - when: { auto_bind_enabled: true, auto_bind_outcome: KEY_MISSING }
        to: S04
        emit:
          note: "缺少业务键字段，无法自动绑定"
      - when: { auto_bind_enabled: true, auto_bind_outcome: KEY_ID_RESOLVE_FAIL }
        to: S05
        emit:
          note: "业务键中的ID字段解析失败"
      - when: { auto_bind_enabled: true, auto_bind_outcome: ZERO, create_enabled: true }
        to: S13
        emit:
          spawn_request: true
          spawn_target_node_state: S06
          note: "自动绑定识别为需创建，进入创建提交中间态"
      - when: { auto_bind_enabled: true, auto_bind_outcome: ZERO, create_enabled: false }
        to: S04
        emit:
          note: "未匹配到候选节点且不允许创建"

  # --- Create prepare ---
  E20:
    stage: create_prepare
    desc: "创建准备阶段2：spawn 成功则提交到 NORMAL；失败保持等待态（不迁移）"
    from: [S13]
    outcomes:
      - when: { spawn_success: true }
        to: S01
        emit:
          note: "创建副作用提交成功"

  E21:
    stage: create_prepare
    desc: "创建依赖解析失败→DEPENDENCY_ERROR"
    from: [S02]
    outcomes:
      - when: { create_enabled: true, data_present: true, create_id_resolve_ok: false }
        to: S05
        emit:
          note: "创建前依赖ID解析失败"

  E22:
    stage: create_prepare
    desc: "孤儿自删准备：从 MISSING 进入 DELETE 执行入口"
    from: [S02]
    outcomes:
      - when: {}
        to: S09
        emit:
          note: "孤儿节点按策略进入自删"

  # --- Update prepare (target-side) ---
  E30:
    stage: update_prepare
    desc: "更新准备：缺data_id/依赖未解析→PRECONDITION_FAILED；有差异→UPDATE"
    from: [S01]
    outcomes:
      - when: { update_enabled: true, target_has_data_id: false }
        to: S08
        emit:
          note: "目标节点缺少data_id"
      - when: { update_enabled: true, target_has_data_id: true, update_id_resolve_ok: false }
        to: S08
        emit:
          note: "更新前依赖ID未解析"
      - when: { update_enabled: true, target_has_data_id: true, update_id_resolve_ok: true, has_diff: true }
        to: S07
        emit:
          note: "检测到数据差异，准备更新"

  # --- Post-create normalization ---
  E41:
    stage: post_create_ready
    desc: "创建成功后归并到 update 起点"
    from: [S11C]
    outcomes:
      - when: { execute_action: CREATE }
        to: S01
        emit:
          note: "创建成功后转入更新起点"

  # --- Sync execute (split by action) ---
  E40C_START:
    stage: sync_execute
    desc: "CREATE 执行入口：进入异步执行中"
    from: [S06]
    outcomes:
      - when: { handler_result: IN_PROGRESS }
        to: S10C
        emit:
          note: "CREATE 进入异步执行中"

  E40C:
    stage: sync_execute
    desc: "CREATE 执行结果回写：进行中/成功/失败"
    from: [S10C]
    outcomes:
      - when: { handler_result: SUCCESS }
        to: S11C
        emit:
          note: "CREATE 执行成功"
      - when: { handler_result: FAILED }
        to: S12C
        emit:
          note: "CREATE 执行失败"

  E40U_START:
    stage: sync_execute
    desc: "UPDATE 执行入口：进入异步执行中"
    from: [S07]
    outcomes:
      - when: { handler_result: IN_PROGRESS }
        to: S10U
        emit:
          note: "UPDATE 进入异步执行中"

  E40U:
    stage: sync_execute
    desc: "UPDATE 执行结果回写：进行中/成功/失败/跳过"
    from: [S10U]
    outcomes:
      - when: { handler_result: SUCCESS }
        to: S11U
        emit:
          note: "UPDATE 执行成功"
      - when: { handler_result: FAILED }
        to: S12U
        emit:
          note: "UPDATE 执行失败"
      - when: { handler_result: SKIPPED }
        to: S14
        emit:
          note: "更新降级并跳过"

  E40D_START:
    stage: sync_execute
    desc: "DELETE 执行入口：进入异步执行中"
    from: [S09]
    outcomes:
      - when: { handler_result: IN_PROGRESS }
        to: S10D
        emit:
          note: "DELETE 进入异步执行中"

  E40D:
    stage: sync_execute
    desc: "DELETE 执行结果回写：进行中/成功/失败"
    from: [S10D]
    outcomes:
      - when: { handler_result: SUCCESS }
        to: S11D
        emit:
          note: "DELETE 执行成功"
          delete_node: true
      - when: { handler_result: FAILED }
        to: S12D
        emit:
          note: "DELETE 执行失败"

invariants:
  INV-1_UNCHECKED_ACTION_NONE:
    desc: "UNCHECKED 不允许有动作"
    when: { binding_status: UNCHECKED }
    require: { action: NONE }

  INV-2_BLOCKING_NO_ACTION:
    desc: "阻断态不允许执行动作"
    when_any:
      - { binding_status: ABNORMAL }
      - { binding_status: WARNING }
      - { binding_status: DEPENDENCY_ERROR }
    require: { action: NONE }

  INV-3_PRECOND_IMPLIES_UPDATE:
    desc: "PRECONDITION_FAILED 必须伴随 action=UPDATE"
    when: { status: PRECONDITION_FAILED }
    require: { action: UPDATE }
