[
  {
    "name": "server.ready",
    "group": "服务生命周期",
    "title": "组件启动完成",
    "description": "应用组件启动后的进程生命周期通知。",
    "timing": "所有应用组件启动后尽力发布。",
    "caveats": [
      "热重载不补发此事件。",
      "订阅建立前或队列繁忙时可能错过；不能把它用作可靠定时任务。"
    ],
    "fields": [],
    "example": {}
  },
  {
    "name": "server.stopping",
    "group": "服务生命周期",
    "title": "服务开始停止",
    "description": "bridge 关闭前的生命周期通知。",
    "timing": "停机流程关闭 bridge 前尽力发布。",
    "caveats": [
      "停机可能来不及消费，不能依赖此事件持久化内存状态。"
    ],
    "fields": [],
    "example": {}
  },
  {
    "name": "game.operation.finished",
    "group": "请求观察",
    "title": "会话任务返回",
    "description": "已进入会话任务队列的处理函数返回。",
    "timing": "会话任务处理器返回后。",
    "caveats": [
      "handler_failed=false 不代表业务成功；正常拒绝也可无错误返回。",
      "插件公告任务被排除，避免递归。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "任务关联角色快照。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "宿主任务来源标识。"
      },
      {
        "name": "handler_failed",
        "type": "boolean",
        "description": "处理器是否返回错误；不是业务结果。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "source": "upper",
      "handler_failed": false
    }
  },
  {
    "name": "gameplay.operation.started",
    "group": "请求观察",
    "title": "玩法模块开始处理",
    "description": "已登记的玩法模块处理器即将执行。",
    "timing": "模块分发选中处理器后、调用前。",
    "caveats": [
      "当前接入 62 个已登记玩法模块，不是原始网络抓包。",
      "不暴露请求包体，不能修改或拒绝请求。",
      "started 的 handler_failed 为 false，无业务成功含义。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "当前选中角色。"
      },
      {
        "name": "module",
        "type": "string",
        "description": "宿主登记的模块名。"
      },
      {
        "name": "transport",
        "type": "string",
        "description": "模块接收的传输路径标识。"
      },
      {
        "name": "opcode",
        "type": "integer (uint16)",
        "description": "请求操作码。"
      },
      {
        "name": "handler_failed",
        "type": "boolean",
        "description": "开始通知为 false。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "module": "inventory",
      "transport": "upper",
      "opcode": 27,
      "handler_failed": false
    }
  },
  {
    "name": "gameplay.operation.finished",
    "group": "请求观察",
    "title": "玩法模块处理返回",
    "description": "已登记玩法模块的处理器已返回。",
    "timing": "模块处理函数返回时。",
    "caveats": [
      "handler_failed=false 也可能是业务被原生规则正常拒绝。",
      "用领域成功事件判断事务结果，不从此通知推断扣费、发奖或回包成功。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "当前角色。"
      },
      {
        "name": "module",
        "type": "string",
        "description": "宿主登记的模块名。"
      },
      {
        "name": "transport",
        "type": "string",
        "description": "传输路径标识。"
      },
      {
        "name": "opcode",
        "type": "integer (uint16)",
        "description": "请求操作码。"
      },
      {
        "name": "handler_failed",
        "type": "boolean",
        "description": "处理器是否以错误返回。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "module": "inventory",
      "transport": "upper",
      "opcode": 27,
      "handler_failed": false
    }
  },
  {
    "name": "character.bound",
    "group": "角色与城镇",
    "title": "角色绑定会话",
    "description": "选中的角色绑定到有效会话。",
    "timing": "角色绑定时，包含重连。",
    "caveats": [
      "data 本身就是 Character，没有 data.character。",
      "不是首次登录、建角或进城完成；重连会再次触发。"
    ],
    "fields": [
      {
        "name": "id",
        "type": "string",
        "description": "角色标识，保留字符串。"
      },
      {
        "name": "channel_id",
        "type": "integer",
        "description": "会话所属频道。"
      }
    ],
    "example": {
      "id": "10001",
      "channel_id": 1
    }
  },
  {
    "name": "character.unbound",
    "group": "角色与城镇",
    "title": "角色开始解绑",
    "description": "当前有效角色会话开始解除绑定。",
    "timing": "角色解绑清理之前取得快照。",
    "caveats": [
      "data 本身就是 Character。",
      "不能保证客户端仍在线，也不能把通知当作可靠离线回调。"
    ],
    "fields": [
      {
        "name": "id",
        "type": "string",
        "description": "解绑角色标识。"
      },
      {
        "name": "channel_id",
        "type": "integer",
        "description": "解绑前所属频道。"
      }
    ],
    "example": {
      "id": "10001",
      "channel_id": 1
    }
  },
  {
    "name": "character.created",
    "group": "角色与城镇",
    "title": "角色创建提交",
    "description": "新角色记录创建事务已提交。",
    "timing": "创建事务提交后、响应前，对新记录发布一次。",
    "caveats": [
      "character 指新建角色，不一定是当前已选中角色。",
      "不表示客户端已收到角色名单。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "新记录的角色 ID 与请求会话频道。"
      },
      {
        "name": "name",
        "type": "string",
        "description": "角色名称。"
      },
      {
        "name": "job",
        "type": "string",
        "description": "仓储角色职业标识。"
      },
      {
        "name": "level",
        "type": "integer",
        "description": "创建后的等级。"
      },
      {
        "name": "slot",
        "type": "integer",
        "description": "角色槽位。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "name": "示例勇士",
      "job": "swordman",
      "level": 1,
      "slot": 0
    }
  },
  {
    "name": "character.deleted",
    "group": "角色与城镇",
    "title": "角色删除提交",
    "description": "角色记录删除已提交。",
    "timing": "删除完成后、角色名单刷新前。",
    "caveats": [
      "character 和资料为被删除角色的快照。",
      "后续不能据此查询或修改已删除记录。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "被删除角色标识。"
      },
      {
        "name": "name",
        "type": "string",
        "description": "删除前名称。"
      },
      {
        "name": "job",
        "type": "string",
        "description": "删除前职业标识。"
      },
      {
        "name": "level",
        "type": "integer",
        "description": "删除前等级。"
      },
      {
        "name": "slot",
        "type": "integer",
        "description": "原角色槽位。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "name": "示例勇士",
      "job": "swordman",
      "level": 1,
      "slot": 0
    }
  },
  {
    "name": "town.area_entered",
    "group": "角色与城镇",
    "title": "城镇区域切换",
    "description": "合法城镇区域切换已接受并完成场景投影发送。",
    "timing": "城镇位置提交及场景投影发送后。",
    "caveats": [
      "重复成功的区域请求可能重复发布；不要用它判断首次到访。",
      "发送完成不等于客户端渲染完成。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "移动角色。"
      },
      {
        "name": "town_id",
        "type": "integer",
        "description": "城镇编号。"
      },
      {
        "name": "area_id",
        "type": "integer",
        "description": "城镇区域编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "town_id": 1,
      "area_id": 2
    }
  },
  {
    "name": "dungeon.entered",
    "group": "副本",
    "title": "初始房间进入",
    "description": "副本初始房间的对象与掉落状态已提交。",
    "timing": "开始地图包发送、初始场景状态提交后，按角色发布。",
    "caveats": [
      "包含已接入的单人、组队和训练直入路径。",
      "不是每次换房通知；进图失败后的退役可另发 exited。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "进入角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "difficulty",
        "type": "integer",
        "description": "请求难度编号。"
      },
      {
        "name": "run_id",
        "type": "string",
        "description": "进程内运行标识，不作持久账本键。"
      },
      {
        "name": "room",
        "type": "string",
        "description": "当前房间 X:Y。"
      },
      {
        "name": "map_id",
        "type": "integer",
        "description": "当前地图 ID；无场景时 0。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否共享组队副本 owner。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "difficulty": 0,
      "run_id": "42",
      "room": "0:0",
      "map_id": 100,
      "party": false
    }
  },
  {
    "name": "dungeon.room_entered",
    "group": "副本",
    "title": "副本房间切换",
    "description": "一次真实的副本换房已经提交。",
    "timing": "换房状态提交后，按实际移动角色发布。",
    "caveats": [
      "重访旧房间也会发布；重复确认包不冒充新换房。",
      "details.revisit 不是首次进入整个副本的标记。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "移动角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "difficulty",
        "type": "integer",
        "description": "难度编号。"
      },
      {
        "name": "run_id",
        "type": "string",
        "description": "运行标识。"
      },
      {
        "name": "room",
        "type": "string",
        "description": "目标房间 X:Y。"
      },
      {
        "name": "map_id",
        "type": "integer",
        "description": "目标地图 ID。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否共享组队 owner。"
      },
      {
        "name": "details.source_room",
        "type": "string",
        "description": "来源房间 X:Y。"
      },
      {
        "name": "details.revisit",
        "type": "boolean",
        "description": "是否重访目标房间。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "difficulty": 0,
      "run_id": "42",
      "room": "1:0",
      "map_id": 101,
      "party": false,
      "details": {
        "source_room": "0:0",
        "revisit": false
      }
    }
  },
  {
    "name": "dungeon.actor_defeated",
    "group": "副本",
    "title": "权威战斗对象死亡",
    "description": "普通战斗 owner 接受对象死亡。",
    "timing": "权威死亡判定接受后、可选奖励和场景投影前。",
    "caveats": [
      "共享世界按对象发布一次，不按每位队员重复发布。",
      "不证明掉落、击杀经验或通关奖励已经提交，也不代表覆盖所有特殊对象退休路径。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "此次接受路径关联角色，不是可靠的最终归属/伤害榜。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "difficulty",
        "type": "integer",
        "description": "难度。"
      },
      {
        "name": "run_id",
        "type": "string",
        "description": "运行标识。"
      },
      {
        "name": "room",
        "type": "string",
        "description": "当前房间。"
      },
      {
        "name": "map_id",
        "type": "integer",
        "description": "当前地图。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否组队。"
      },
      {
        "name": "details.object_key",
        "type": "integer",
        "description": "运行时对象键。"
      },
      {
        "name": "details.actor_kind",
        "type": "string",
        "description": "战斗对象分类标识。"
      },
      {
        "name": "details.boss",
        "type": "boolean",
        "description": "此次是否为 Boss 对象死亡。"
      },
      {
        "name": "details.room_cleared",
        "type": "boolean",
        "description": "此次死亡后房间是否清空。"
      },
      {
        "name": "details.monster_id",
        "type": "integer",
        "description": "用于此次掉落判定的怪物模板编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "difficulty": 0,
      "run_id": "42",
      "room": "1:0",
      "map_id": 101,
      "party": true,
      "details": {
        "object_key": 100,
        "actor_kind": "monster",
        "boss": false,
        "room_cleared": true,
        "monster_id": 200
      }
    }
  },
  {
    "name": "dungeon.pickup_committed",
    "group": "副本",
    "title": "掉落拾取提交",
    "description": "拾取持久化完成，掉落对象已被消费。",
    "timing": "拾取资产提交及掉落消费后、响应前。",
    "caveats": [
      "重复拾取收据重放不重复发布。",
      "details 描述此次局部拾取，不是完整背包快照；金币拾取也可能没有有效目标槽。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "拾取角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "difficulty",
        "type": "integer",
        "description": "难度。"
      },
      {
        "name": "run_id",
        "type": "string",
        "description": "运行标识。"
      },
      {
        "name": "room",
        "type": "string",
        "description": "发布时当前场景。"
      },
      {
        "name": "map_id",
        "type": "integer",
        "description": "发布时地图。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否组队。"
      },
      {
        "name": "details.object_key",
        "type": "integer",
        "description": "被消费掉落对象键。"
      },
      {
        "name": "details.item_id",
        "type": "integer",
        "description": "掉落物品模板 ID。"
      },
      {
        "name": "details.amount",
        "type": "integer",
        "description": "掉落数量/金额。"
      },
      {
        "name": "details.destination_slot",
        "type": "integer",
        "description": "owner 返回的目标槽。"
      },
      {
        "name": "details.gold_after",
        "type": "integer",
        "description": "owner 返回的拾取后金币快照。"
      },
      {
        "name": "details.pickup_room",
        "type": "string",
        "description": "拾取计划所在房间。"
      },
      {
        "name": "details.pickup_map_id",
        "type": "integer",
        "description": "拾取计划所在地图 ID。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "difficulty": 0,
      "run_id": "42",
      "room": "1:0",
      "map_id": 101,
      "party": false,
      "details": {
        "object_key": 300,
        "item_id": 400,
        "amount": 1,
        "destination_slot": 10,
        "gold_after": 10000,
        "pickup_room": "1:0",
        "pickup_map_id": 101
      }
    }
  },
  {
    "name": "dungeon.character_died",
    "group": "副本",
    "title": "角色死亡被接受",
    "description": "角色死亡状态与死亡状态发送被接受。",
    "timing": "合法死亡报告推进死亡状态并发送状态后。",
    "caveats": [
      "同一死亡状态的重复报告不重复发布。",
      "此事件不包含击杀者、伤害明细或损失资产。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "死亡角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "difficulty",
        "type": "integer",
        "description": "难度。"
      },
      {
        "name": "run_id",
        "type": "string",
        "description": "运行标识。"
      },
      {
        "name": "room",
        "type": "string",
        "description": "死亡时房间。"
      },
      {
        "name": "map_id",
        "type": "integer",
        "description": "死亡时地图。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否组队。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "difficulty": 0,
      "run_id": "42",
      "room": "1:0",
      "map_id": 101,
      "party": false
    }
  },
  {
    "name": "dungeon.character_revived",
    "group": "副本",
    "title": "角色复活完成",
    "description": "复活扣费及响应序列已经提交。",
    "timing": "owner 完成复活扣费和响应序列后。",
    "caveats": [
      "响应重试只发布一次接受的复活。",
      "coin_consumed 是布尔值，不是消耗数量。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "复活角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "difficulty",
        "type": "integer",
        "description": "难度。"
      },
      {
        "name": "run_id",
        "type": "string",
        "description": "运行标识。"
      },
      {
        "name": "room",
        "type": "string",
        "description": "当前房间。"
      },
      {
        "name": "map_id",
        "type": "integer",
        "description": "当前地图。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否组队。"
      },
      {
        "name": "details.coin_consumed",
        "type": "boolean",
        "description": "是否消费复活币。"
      },
      {
        "name": "details.free_revive",
        "type": "boolean",
        "description": "是否免费复活。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "difficulty": 0,
      "run_id": "42",
      "room": "1:0",
      "map_id": 101,
      "party": false,
      "details": {
        "coin_consumed": true,
        "free_revive": false
      }
    }
  },
  {
    "name": "dungeon.exited",
    "group": "副本",
    "title": "副本运行退役",
    "description": "当前副本运行首次被退役，并保留最后场景和原因。",
    "timing": "runtime 第一次进入退役边界时。",
    "caveats": [
      "包含返回城镇、运行替换、断线和回滚，不等于通关或成功结算。",
      "reason 为当前宿主路径标识；不要仅凭字符串猜测资产结果。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "关联角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "退出副本。"
      },
      {
        "name": "difficulty",
        "type": "integer",
        "description": "难度。"
      },
      {
        "name": "run_id",
        "type": "string",
        "description": "退役运行标识。"
      },
      {
        "name": "room",
        "type": "string",
        "description": "最后可用房间，可能为空。"
      },
      {
        "name": "map_id",
        "type": "integer",
        "description": "最后可用地图，无场景时 0。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否组队。"
      },
      {
        "name": "details.reason",
        "type": "string",
        "description": "退役原因标识。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "difficulty": 0,
      "run_id": "42",
      "room": "1:0",
      "map_id": 101,
      "party": false,
      "details": {
        "reason": "return_to_town"
      }
    }
  },
  {
    "name": "dungeon.cleared",
    "group": "副本",
    "title": "权威通关",
    "description": "副本运行权威判定通关。",
    "timing": "普通 Boss、无 Boss 教学及祭坛已接入的播报入口；共享队伍运行去重。",
    "caveats": [
      "奖励可能尚未结算；不是全部攻坚结算的总入口。",
      "elapsed_ms 未知时为 nil，不应当作 0 秒。",
      "自定义通关播报可用 dungeon.clear_announcement Hook，避免与内置公告重复。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "该次通关发布关联角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "dungeon_name",
        "type": "string",
        "description": "副本名称。"
      },
      {
        "name": "player_name",
        "type": "string",
        "description": "角色名称。"
      },
      {
        "name": "party",
        "type": "boolean",
        "description": "是否共享组队运行。"
      },
      {
        "name": "elapsed_ms",
        "type": "integer | nil",
        "description": "已知通关用时毫秒；未知为 nil。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "通关发布来源标识。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "dungeon_name": "示例地下城",
      "player_name": "示例勇士",
      "party": false,
      "elapsed_ms": 90000,
      "source": "boss_death"
    }
  },
  {
    "name": "dungeon.settlement_committed",
    "group": "副本",
    "title": "通关成长结算提交",
    "description": "本角色通关成长事务已新提交。",
    "timing": "通关成长事务提交后；收据重放不重复发布。",
    "caveats": [
      "不覆盖后续独立翻牌或塔奖励事务。",
      "experience 是本次成长提交经验增量，不等于经验 Hook 的基础 amount。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "结算角色。"
      },
      {
        "name": "dungeon_id",
        "type": "integer",
        "description": "副本 ID。"
      },
      {
        "name": "completion_key",
        "type": "string",
        "description": "核心结算完成标识，仅作观察，不赋予插件资产写入能力。"
      },
      {
        "name": "experience",
        "type": "integer (uint32)",
        "description": "本次提交的经验增量。"
      },
      {
        "name": "level",
        "type": "integer",
        "description": "成长事务后的角色等级。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "dungeon_id": 10,
      "completion_key": "example-completion",
      "experience": 1200,
      "level": 10
    }
  },
  {
    "name": "inventory.operation_applied",
    "group": "物品与成长",
    "title": "背包操作已应用",
    "description": "背包 owner 已应用一项合法操作。",
    "timing": "显式 owner 成功路径、网络响应发送前。",
    "caveats": [
      "包含成功无操作，拒绝与回滚不发布。",
      "item_id 为字符串；0 值或槽位 0 不保证代表真实源/目标对象。",
      "不提供增减数量、完整奖励或背包差量。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "owner 操作标识，如 move_itemspace / sort_item；具体值由当前接入 owner 决定。"
      },
      {
        "name": "item_id",
        "type": "string",
        "description": "局部物品模板标识，未提供时为字符串 0。"
      },
      {
        "name": "source_list",
        "type": "integer (uint8)",
        "description": "源列表类型。"
      },
      {
        "name": "source_slot",
        "type": "integer (int16)",
        "description": "源槽位。"
      },
      {
        "name": "target_list",
        "type": "integer (uint8)",
        "description": "目标列表类型。"
      },
      {
        "name": "target_slot",
        "type": "integer (int16)",
        "description": "目标槽位。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "operation": "move_itemspace",
      "item_id": "400",
      "source_list": 0,
      "source_slot": 10,
      "target_list": 0,
      "target_slot": 11
    }
  },
  {
    "name": "equipment.operation_applied",
    "group": "物品与成长",
    "title": "装备操作已应用",
    "description": "装备 owner 已接受并应用操作结果。",
    "timing": "合法操作应用或资产事务提交后，响应前。",
    "caveats": [
      "随机强化/锻造失败但成本已扣或装备已损坏也发布，不表示强化成功。",
      "可包含成功无操作；拒绝/回滚不发布。",
      "没有 UpgradeSucceeded 字段，不要自行从 operation 推断随机结果。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "如 upgrade_item、equipment_regeneration、equipment_socket_open。"
      },
      {
        "name": "item_id",
        "type": "string",
        "description": "局部模板标识，未提供时 0。"
      },
      {
        "name": "source_list",
        "type": "integer (uint8)",
        "description": "源列表。"
      },
      {
        "name": "source_slot",
        "type": "integer (int16)",
        "description": "源槽位。"
      },
      {
        "name": "target_list",
        "type": "integer (uint8)",
        "description": "目标列表。"
      },
      {
        "name": "target_slot",
        "type": "integer (int16)",
        "description": "目标槽位。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "operation": "upgrade_item",
      "item_id": "400",
      "source_list": 0,
      "source_slot": 10,
      "target_list": 0,
      "target_slot": 0
    }
  },
  {
    "name": "skill.operation_applied",
    "group": "物品与成长",
    "title": "技能操作已应用",
    "description": "技能 owner 已应用解码后的合法操作。",
    "timing": "技能 owner 成功处理后、响应前。",
    "caveats": [
      "可包含成功无操作；不提供完整技能树、SP/TP 差量。",
      "通用物品/槽位字段不适用时为零。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "当前技能 owner 的操作标识。"
      },
      {
        "name": "item_id",
        "type": "string",
        "description": "不适用时 0。"
      },
      {
        "name": "source_list",
        "type": "integer",
        "description": "不适用时 0。"
      },
      {
        "name": "source_slot",
        "type": "integer",
        "description": "不适用时 0。"
      },
      {
        "name": "target_list",
        "type": "integer",
        "description": "不适用时 0。"
      },
      {
        "name": "target_slot",
        "type": "integer",
        "description": "不适用时 0。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "operation": "buy_skill",
      "item_id": "0",
      "source_list": 0,
      "source_slot": 0,
      "target_list": 0,
      "target_slot": 0
    }
  },
  {
    "name": "cargo.operation_applied",
    "group": "物品与成长",
    "title": "仓库操作已应用",
    "description": "仓库 owner 已应用操作。",
    "timing": "仓库 owner 成功处理后、响应前。",
    "caveats": [
      "可包含成功无操作；通用字段不等于完整存取金额或仓库差量。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "如 deposit_money、withdraw_money、create_account_cargo。"
      },
      {
        "name": "item_id",
        "type": "string",
        "description": "未提供时 0。"
      },
      {
        "name": "source_list",
        "type": "integer",
        "description": "局部源列表元数据。"
      },
      {
        "name": "source_slot",
        "type": "integer",
        "description": "局部源槽位元数据。"
      },
      {
        "name": "target_list",
        "type": "integer",
        "description": "局部目标列表元数据。"
      },
      {
        "name": "target_slot",
        "type": "integer",
        "description": "局部目标槽位元数据。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "operation": "deposit_money",
      "item_id": "0",
      "source_list": 0,
      "source_slot": 0,
      "target_list": 0,
      "target_slot": 0
    }
  },
  {
    "name": "pet.operation_applied",
    "group": "物品与成长",
    "title": "宠物操作已应用",
    "description": "宠物 owner 已应用操作。",
    "timing": "显式宠物成功路径、响应前。",
    "caveats": [
      "可包含成功无操作；不包含宠物完整属性或改名正文。",
      "未提供的通用目标字段为零。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "如 seal_creature。"
      },
      {
        "name": "item_id",
        "type": "string",
        "description": "宠物相关模板标识，可能为 0。"
      },
      {
        "name": "source_list",
        "type": "integer",
        "description": "源列表类型。"
      },
      {
        "name": "source_slot",
        "type": "integer",
        "description": "源槽位。"
      },
      {
        "name": "target_list",
        "type": "integer",
        "description": "目标列表类型。"
      },
      {
        "name": "target_slot",
        "type": "integer",
        "description": "目标槽位。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "operation": "seal_creature",
      "item_id": "500",
      "source_list": 7,
      "source_slot": 1,
      "target_list": 0,
      "target_slot": 0
    }
  },
  {
    "name": "craft.operation_applied",
    "group": "物品与成长",
    "title": "制作配方提交",
    "description": "制作 owner 已成功提交一项已接入配方。",
    "timing": "配方事务提交后、响应前。",
    "caveats": [
      "不提供完整材料消耗或产物清单。",
      "勋章合成等配方结果仍以核心为准，不从此事件另发奖励。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "制作角色。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "例如 compound_emblems。"
      },
      {
        "name": "item_id",
        "type": "string",
        "description": "局部模板标识，未提供时 0。"
      },
      {
        "name": "source_list",
        "type": "integer",
        "description": "未提供时 0。"
      },
      {
        "name": "source_slot",
        "type": "integer",
        "description": "未提供时 0。"
      },
      {
        "name": "target_list",
        "type": "integer",
        "description": "未提供时 0。"
      },
      {
        "name": "target_slot",
        "type": "integer",
        "description": "未提供时 0。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "operation": "compound_emblems",
      "item_id": "0",
      "source_list": 0,
      "source_slot": 0,
      "target_list": 0,
      "target_slot": 0
    }
  },
  {
    "name": "quest.accepted",
    "group": "任务",
    "title": "接受新任务",
    "description": "一代新任务状态已接受并持久化。",
    "timing": "任务接受持久化后。",
    "caveats": [
      "幂等的重复接受不发布。",
      "progress 当前接受路径为 0。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "接受任务角色。"
      },
      {
        "name": "quest_id",
        "type": "integer (uint16)",
        "description": "任务 ID。"
      },
      {
        "name": "progress",
        "type": "integer (int64)",
        "description": "接受路径为 0，不是完整任务目标列表。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "quest_id": 100,
      "progress": 0
    }
  },
  {
    "name": "quest.progressed",
    "group": "任务",
    "title": "任务触发进度变化",
    "description": "显式任务触发器改变并保存进度。",
    "timing": "显式触发产生实际变化并持久化后。",
    "caveats": [
      "未改变状态的触发不发布。",
      "progress 是该触发器返回值，不是所有任务目标的统一百分比。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "任务角色。"
      },
      {
        "name": "quest_id",
        "type": "integer (uint16)",
        "description": "任务 ID。"
      },
      {
        "name": "progress",
        "type": "integer (int64)",
        "description": "本次 owner 返回的进度值。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "quest_id": 100,
      "progress": 3
    }
  },
  {
    "name": "quest.finished",
    "group": "任务",
    "title": "任务结算提交",
    "description": "完成任务结算事务已新提交。",
    "timing": "任务结算事务提交后。",
    "caveats": [
      "收据重放不重复发布。",
      "不包含实际任务奖励清单；progress 当前为 0。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "完成任务角色。"
      },
      {
        "name": "quest_id",
        "type": "integer (uint16)",
        "description": "任务 ID。"
      },
      {
        "name": "progress",
        "type": "integer (int64)",
        "description": "当前完成路径为 0。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "quest_id": 100,
      "progress": 0
    }
  },
  {
    "name": "quest.abandoned",
    "group": "任务",
    "title": "放弃任务提交",
    "description": "任务放弃结算事务已提交。",
    "timing": "任务放弃事务提交后。",
    "caveats": [
      "progress 当前为 0，不表示任务之前没有进度。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "放弃任务角色。"
      },
      {
        "name": "quest_id",
        "type": "integer (uint16)",
        "description": "任务 ID。"
      },
      {
        "name": "progress",
        "type": "integer (int64)",
        "description": "当前放弃路径为 0。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "quest_id": 100,
      "progress": 0
    }
  },
  {
    "name": "commerce.shop_purchased",
    "group": "商业与交易",
    "title": "商店购买提交",
    "description": "NPC、秘密商店或 Cera 商城结账已提交。",
    "timing": "owner 结账提交后、socket 发布前。",
    "caveats": [
      "items 仅主商品，不含额外赠品。",
      "这是成功购买通知；Cera 购买 Hook 的请求行只有 commodity_id/count=1，语义不同。",
      "不包含价格、余额或原始支付凭据。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "购买角色。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "npc / secret / cera。"
      },
      {
        "name": "items",
        "type": "CommerceItem[]",
        "description": "主商品行数组。"
      },
      {
        "name": "items[].item_id",
        "type": "integer (uint32)",
        "description": "实际商品模板 ID。"
      },
      {
        "name": "items[].count",
        "type": "integer (uint32)",
        "description": "实际该行商品数量。"
      },
      {
        "name": "items[].commodity_id",
        "type": "integer (uint32) | nil",
        "description": "Cera 商品编号；零值省略。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "source": "cera",
      "items": [
        {
          "item_id": 400,
          "count": 2,
          "commodity_id": 1000
        }
      ]
    }
  },
  {
    "name": "commerce.shop_sold",
    "group": "商业与交易",
    "title": "NPC 出售提交",
    "description": "向 NPC 出售物品已提交。",
    "timing": "出售事务提交后、socket 发布前。",
    "caveats": [
      "count 为实际出售量，不提供售价或售后金币余额。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "出售角色。"
      },
      {
        "name": "item_id",
        "type": "integer (uint32)",
        "description": "出售物品模板 ID。"
      },
      {
        "name": "count",
        "type": "integer (uint32)",
        "description": "实际出售数量。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "item_id": 400,
      "count": 2
    }
  },
  {
    "name": "commerce.auction_registered",
    "group": "商业与交易",
    "title": "拍卖或金币寄售上架",
    "description": "商品拍卖或金币寄售上架已提交。",
    "timing": "拍卖 owner 上架提交后。",
    "caveats": [
      "不提供价格、账号或资产明细。",
      "source=gold 的 count 当前为 1，并不是寄售金币金额。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "item / gold。"
      },
      {
        "name": "listing_id",
        "type": "string",
        "description": "上架记录 uint64 ID 的字符串。"
      },
      {
        "name": "seller_id",
        "type": "string",
        "description": "卖方角色标识。"
      },
      {
        "name": "item_id",
        "type": "integer (int64)",
        "description": "owner 上架模板标识。"
      },
      {
        "name": "count",
        "type": "integer (int64)",
        "description": "商品数量；gold 为 1。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "source": "item",
      "listing_id": "900000000000001",
      "seller_id": "10001",
      "item_id": 400,
      "count": 2
    }
  },
  {
    "name": "commerce.auction_cancelled",
    "group": "商业与交易",
    "title": "拍卖或寄售取消",
    "description": "商品拍卖或金币寄售取消已提交。",
    "timing": "取消事务提交后。",
    "caveats": [
      "退还邮件可能仍在等待重试，不保证已经收信。",
      "source=gold 的 count 为 1，不是金币金额。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "取消操作角色。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "item / gold。"
      },
      {
        "name": "listing_id",
        "type": "string",
        "description": "上架记录 ID。"
      },
      {
        "name": "seller_id",
        "type": "string",
        "description": "卖方角色 ID。"
      },
      {
        "name": "item_id",
        "type": "integer (int64)",
        "description": "上架模板标识。"
      },
      {
        "name": "count",
        "type": "integer (int64)",
        "description": "商品数量；gold 为 1。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "source": "item",
      "listing_id": "900000000000001",
      "seller_id": "10001",
      "item_id": 400,
      "count": 2
    }
  },
  {
    "name": "commerce.auction_bid",
    "group": "商业与交易",
    "title": "商品拍卖竞价提交",
    "description": "商品拍卖的一次新竞价已提交。",
    "timing": "拍卖竞价 owner 提交后。",
    "caveats": [
      "仅商品拍卖竞价；退款邮件可能仍待重试。",
      "不表示本次出价最终获胜，也不提供竞价金额。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "出价角色。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "此路径为 item。"
      },
      {
        "name": "listing_id",
        "type": "string",
        "description": "上架记录 ID。"
      },
      {
        "name": "seller_id",
        "type": "string",
        "description": "卖方角色 ID。"
      },
      {
        "name": "item_id",
        "type": "integer (int64)",
        "description": "商品模板。"
      },
      {
        "name": "count",
        "type": "integer (int64)",
        "description": "商品数量。"
      }
    ],
    "example": {
      "character": {
        "id": "10002",
        "channel_id": 1
      },
      "source": "item",
      "listing_id": "900000000000001",
      "seller_id": "10001",
      "item_id": 400,
      "count": 2
    }
  },
  {
    "name": "commerce.auction_purchased",
    "group": "商业与交易",
    "title": "拍卖直购或寄售购买",
    "description": "商品拍卖一口价或金币寄售购买已提交。",
    "timing": "购买事务提交后。",
    "caveats": [
      "邮件发货可能待重试，不是背包到账确认。",
      "商品路径优先用 delivery 商品快照；gold 的 count 为 1。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "购买角色。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "item / gold。"
      },
      {
        "name": "listing_id",
        "type": "string",
        "description": "上架记录 ID。"
      },
      {
        "name": "seller_id",
        "type": "string",
        "description": "卖方角色 ID。"
      },
      {
        "name": "item_id",
        "type": "integer (int64)",
        "description": "成交模板标识。"
      },
      {
        "name": "count",
        "type": "integer (int64)",
        "description": "成交商品量；gold 为 1。"
      }
    ],
    "example": {
      "character": {
        "id": "10002",
        "channel_id": 1
      },
      "source": "item",
      "listing_id": "900000000000001",
      "seller_id": "10001",
      "item_id": 400,
      "count": 2
    }
  },
  {
    "name": "commerce.private_store_opened",
    "group": "商业与交易",
    "title": "摊位生效",
    "description": "私人商店进入生效状态。",
    "timing": "摊位激活时。",
    "caveats": [
      "只描述内存状态，不是资产交易提交。",
      "相同内容完成开摊的重试不重复发布；item_id/count 不适用并省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "开摊角色。"
      },
      {
        "name": "seller_id",
        "type": "string",
        "description": "摊主角色 ID。"
      },
      {
        "name": "rows",
        "type": "integer",
        "description": "摊位商品行数。"
      },
      {
        "name": "item_id",
        "type": "integer | nil",
        "description": "此事件通常省略。"
      },
      {
        "name": "count",
        "type": "integer | nil",
        "description": "此事件通常省略。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "seller_id": "10001",
      "rows": 2
    }
  },
  {
    "name": "commerce.private_store_closed",
    "group": "商业与交易",
    "title": "摊位关闭",
    "description": "一个生效摊位被移除。",
    "timing": "首次移除当前活动摊位时。",
    "caveats": [
      "包含手动、售罄及断线关闭，重复关闭不重复发布。",
      "内存状态通知，rows 可为售罄后的 0；item_id/count 通常省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "摊主快照。"
      },
      {
        "name": "seller_id",
        "type": "string",
        "description": "摊主角色 ID。"
      },
      {
        "name": "rows",
        "type": "integer",
        "description": "关闭时摊位行数。"
      },
      {
        "name": "item_id",
        "type": "integer | nil",
        "description": "通常省略。"
      },
      {
        "name": "count",
        "type": "integer | nil",
        "description": "通常省略。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "seller_id": "10001",
      "rows": 0
    }
  },
  {
    "name": "commerce.private_store_purchased",
    "group": "商业与交易",
    "title": "摊位购买提交",
    "description": "私人商店资产交换已新提交。",
    "timing": "资产交换提交后、投影前。",
    "caveats": [
      "收据重放不重复发布。",
      "rows 当前为 1，不是摊位剩余总行数；不提供价格。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "购买角色。"
      },
      {
        "name": "seller_id",
        "type": "string",
        "description": "摊主角色 ID。"
      },
      {
        "name": "rows",
        "type": "integer",
        "description": "此次成交行数，当前 1。"
      },
      {
        "name": "item_id",
        "type": "integer (int64) | nil",
        "description": "成交物品模板，零值会省略。"
      },
      {
        "name": "count",
        "type": "integer (uint32) | nil",
        "description": "成交数量，零值会省略。"
      }
    ],
    "example": {
      "character": {
        "id": "10002",
        "channel_id": 1
      },
      "seller_id": "10001",
      "rows": 1,
      "item_id": 400,
      "count": 2
    }
  },
  {
    "name": "commerce.trade_committed",
    "group": "商业与交易",
    "title": "双角色交易提交",
    "description": "双方物品与资产交换已原子提交。",
    "timing": "新交易提交后、双方投影之前。",
    "caveats": [
      "无顶层 character 字段，只有双方 ID。",
      "条目数不表示物品总数量，也不包含金币值或道具明细。"
    ],
    "fields": [
      {
        "name": "first_character_id",
        "type": "string",
        "description": "第一方角色 ID。"
      },
      {
        "name": "second_character_id",
        "type": "string",
        "description": "第二方角色 ID。"
      },
      {
        "name": "first_item_rows",
        "type": "integer",
        "description": "第一方出价物品行数。"
      },
      {
        "name": "second_item_rows",
        "type": "integer",
        "description": "第二方出价物品行数。"
      }
    ],
    "example": {
      "first_character_id": "10001",
      "second_character_id": "10002",
      "first_item_rows": 1,
      "second_item_rows": 2
    }
  },
  {
    "name": "commerce.package_opened",
    "group": "商业与交易",
    "title": "Cera 礼包开启提交",
    "description": "Cera 礼包消耗和奖励已提交。",
    "timing": "礼包事务提交后、投影前。",
    "caveats": [
      "只覆盖已接入 Cera 礼包路径，非所有罐子/礼包的统一事件。",
      "overflow_mail=true 表示存在溢出邮件，邮件通知可能尚未送达。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "开礼包角色。"
      },
      {
        "name": "item_id",
        "type": "integer (uint32)",
        "description": "礼包源物品模板。"
      },
      {
        "name": "reward_rows",
        "type": "integer",
        "description": "奖励行数。"
      },
      {
        "name": "reward_units",
        "type": "integer (uint64)",
        "description": "奖励总单位数；Lua number 处理极大整数时需留意精度。"
      },
      {
        "name": "overflow_mail",
        "type": "boolean",
        "description": "是否生成背包溢出邮件。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "item_id": 500,
      "reward_rows": 2,
      "reward_units": 10,
      "overflow_mail": false
    }
  },
  {
    "name": "mail.sent",
    "group": "邮件",
    "title": "玩家邮件发送提交",
    "description": "玩家发信 owner 已提交。",
    "timing": "发信 owner 成功提交后、投影前。",
    "caveats": [
      "不暴露正文、标题或收件人姓名。",
      "多收件请求也不应据单一 recipient_id 推断完整收件名单；claim_rows 此路径省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "发信角色。"
      },
      {
        "name": "recipient_id",
        "type": "string | nil",
        "description": "owner 返回的通知收件角色标识；可选。"
      },
      {
        "name": "claim_rows",
        "type": "integer | nil",
        "description": "提取使用字段，发信通常省略。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "recipient_id": "10002"
    }
  },
  {
    "name": "mail.claimed",
    "group": "邮件",
    "title": "非空邮件附件提取",
    "description": "玩家邮箱一次非空提取已提交。",
    "timing": "邮箱提取提交、产生成功且行数大于 0 的结果后，投影前。",
    "caveats": [
      "空提取不发布；不提供附件明细或邮件正文。",
      "claim_rows 是提取行数，不是物品总数量；recipient_id 通常省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "提取角色。"
      },
      {
        "name": "claim_rows",
        "type": "integer (uint32)",
        "description": "非空提取行数。"
      },
      {
        "name": "recipient_id",
        "type": "string | nil",
        "description": "此路径通常省略。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "claim_rows": 2
    }
  },
  {
    "name": "mail.opened",
    "group": "邮件",
    "title": "邮箱打开快照",
    "description": "邮箱 owner 接受打开请求并生成快照。",
    "timing": "成功邮箱快照产生后、投影前。",
    "caveats": [
      "这是读取观察，不是资产变化或领取成功。",
      "重复打开可再次通知，不提供邮件列表或正文。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "打开邮箱角色。"
      },
      {
        "name": "recipient_id",
        "type": "string | nil",
        "description": "此路径通常省略。"
      },
      {
        "name": "claim_rows",
        "type": "integer | nil",
        "description": "此路径通常省略。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      }
    }
  },
  {
    "name": "party.member_joined",
    "group": "队伍与社交",
    "title": "成员加入队伍",
    "description": "中央队伍 owner 接受新成员加入。",
    "timing": "中央成员状态接受后。",
    "caveats": [
      "这是队伍内存状态，不是副本入场或资产事务。",
      "member_ids 为提交后的当前角色名单。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "本次加入角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "队伍 ID。"
      },
      {
        "name": "target_id",
        "type": "string",
        "description": "加入角色 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "当前角色成员名单；空名单可能省略。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "join 或 peer_accept。"
      }
    ],
    "example": {
      "character": {
        "id": "10002",
        "channel_id": 1
      },
      "group_id": "10",
      "target_id": "10002",
      "member_ids": [
        "10001",
        "10002"
      ],
      "operation": "join"
    }
  },
  {
    "name": "party.member_left",
    "group": "队伍与社交",
    "title": "成员离开队伍",
    "description": "中央队伍 owner 接受离队或踢人。",
    "timing": "成员移除接受后、响应前。",
    "caveats": [
      "character 在主动离队与踢人路径可分别关联离队者或操作者；以 target_id 判断被移除者。",
      "解散后名单为空时 member_ids 可能省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "当前路径关联会话角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "owner 返回的队伍标识。"
      },
      {
        "name": "target_id",
        "type": "string",
        "description": "被移除角色 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "当前剩余名单。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "leave / kick。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "10",
      "target_id": "10002",
      "member_ids": [
        "10001"
      ],
      "operation": "kick"
    }
  },
  {
    "name": "party.leader_changed",
    "group": "队伍与社交",
    "title": "队长转让",
    "description": "中央队伍 owner 已接受队长转让。",
    "timing": "队长状态改变后、响应前。",
    "caveats": [
      "target_id 为新队长，character 可为发起转让的旧队长。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作会话角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "队伍 ID。"
      },
      {
        "name": "target_id",
        "type": "string",
        "description": "新队长角色 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "当前成员名单。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "transfer。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "10",
      "target_id": "10002",
      "member_ids": [
        "10001",
        "10002"
      ],
      "operation": "transfer"
    }
  },
  {
    "name": "guild.created",
    "group": "队伍与社交",
    "title": "公会创建提交",
    "description": "公会 registry 与创建扣费已提交。",
    "timing": "公会创建成功后、响应前。",
    "caveats": [
      "不提供公会名称或完整初始名单。",
      "target_id、member_ids、details 不适用时省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "创建角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "公会 ID。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "create。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "50",
      "operation": "create"
    }
  },
  {
    "name": "guild.application_decided",
    "group": "队伍与社交",
    "title": "公会申请处理",
    "description": "公会申请批准或拒绝已提交。",
    "timing": "申请决策提交后、响应前。",
    "caveats": [
      "拒绝申请也是成功提交的决策；检查 operation。",
      "不提供申请正文或申请人资料。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "处理申请的角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "公会 ID。"
      },
      {
        "name": "target_id",
        "type": "string",
        "description": "被处理申请的角色 ID。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "approve / deny。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "50",
      "target_id": "10002",
      "operation": "approve"
    }
  },
  {
    "name": "guild.member_left",
    "group": "队伍与社交",
    "title": "公会成员离开",
    "description": "离开公会或踢人已提交。",
    "timing": "移除成员提交后、响应前。",
    "caveats": [
      "以 target_id 判断被移除成员，character 是操作路径关联角色。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "公会 ID。"
      },
      {
        "name": "target_id",
        "type": "string",
        "description": "被移除角色 ID。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "leave / kick。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "50",
      "target_id": "10002",
      "operation": "kick"
    }
  },
  {
    "name": "guild.disbanded",
    "group": "队伍与社交",
    "title": "公会解散提交",
    "description": "公会解散已提交。",
    "timing": "解散提交后、响应前。",
    "caveats": [
      "member_ids 是解散前原名单，不是仍在公会的名单。",
      "空名单可能省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "解散操作角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "被解散公会 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "解散前成员名单。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "disband。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "50",
      "member_ids": [
        "10001",
        "10002"
      ],
      "operation": "disband"
    }
  },
  {
    "name": "wedding.changed",
    "group": "队伍与社交",
    "title": "婚姻状态提交",
    "description": "婚姻事务提交后，按发生变更的角色发布。",
    "timing": "婚姻 owner 事务提交后。",
    "caveats": [
      "一项双方变更可按角色发布多条。",
      "离线角色 channel_id 可为 0；operation 是原生婚姻操作编号字符串，非可调用命令。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "发生变更的角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "记录中的 wedding_id 字符串。"
      },
      {
        "name": "target_id",
        "type": "string",
        "description": "记录中的配偶 ID 字符串，未关联可为 0。"
      },
      {
        "name": "operation",
        "type": "string",
        "description": "原生婚姻操作字节的十进制字符串。"
      },
      {
        "name": "details.status",
        "type": "integer",
        "description": "记录的 wedding_state。"
      },
      {
        "name": "details.ring",
        "type": "integer",
        "description": "记录的 wedding_ring。"
      },
      {
        "name": "details.love",
        "type": "integer",
        "description": "记录的 wedding_love。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 0
      },
      "group_id": "60",
      "target_id": "10002",
      "operation": "1",
      "details": {
        "status": 1,
        "ring": 1,
        "love": 10
      }
    }
  },
  {
    "name": "pvp.room_joined",
    "group": "PVP 与攻坚",
    "title": "加入 PVP 房间",
    "description": "PVP 房间成员状态已接受。",
    "timing": "成员加入后、房间状态投影前。",
    "caveats": [
      "包含房间创建者和自动匹配；不是开赛通知。",
      "当前成员快照不包含角色详细资料。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "加入角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "房间 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "当前房间角色名单。"
      },
      {
        "name": "details.seat",
        "type": "integer",
        "description": "加入座位。"
      },
      {
        "name": "details.created",
        "type": "boolean",
        "description": "是否为创建房间路径。"
      },
      {
        "name": "details.battle_mode",
        "type": "integer",
        "description": "原生战斗模式编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "70",
      "member_ids": [
        "10001"
      ],
      "details": {
        "seat": 0,
        "created": true,
        "battle_mode": 1
      }
    }
  },
  {
    "name": "pvp.room_left",
    "group": "PVP 与攻坚",
    "title": "离开 PVP 房间",
    "description": "PVP 房间成员首次被移除。",
    "timing": "房间有效成员首次进入移除路径时。",
    "caveats": [
      "包含断线和练习房，重复移除不重复通知。",
      "当前发布点在实际移除前，member_ids 包含即将离开的角色，不是剩余名单；空名单省略。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "离开角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "房间 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "进入移除路径时的房间名单，含离开者。"
      },
      {
        "name": "details.seat",
        "type": "integer",
        "description": "原座位。"
      },
      {
        "name": "details.battle_mode",
        "type": "integer",
        "description": "原生战斗模式编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10002",
        "channel_id": 1
      },
      "group_id": "70",
      "member_ids": [
        "10001",
        "10002"
      ],
      "details": {
        "seat": 1,
        "battle_mode": 1
      }
    }
  },
  {
    "name": "pvp.match_started",
    "group": "PVP 与攻坚",
    "title": "PVP 比赛开始",
    "description": "准备和地图验证完成，比赛开始状态被接受。",
    "timing": "准备/地图验证后、开始包发送前，每场一次。",
    "caveats": [
      "character 为发布路径的 owner 角色，不按每位玩家重复。",
      "不保证所有客户端成功收到开始包。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "比赛 owner 关联角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "房间 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "参赛房间成员快照。"
      },
      {
        "name": "details.map_id",
        "type": "integer",
        "description": "选中的 PVP 地图 ID。"
      },
      {
        "name": "details.battle_mode",
        "type": "integer",
        "description": "战斗模式编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "70",
      "member_ids": [
        "10001",
        "10002"
      ],
      "details": {
        "map_id": 100,
        "battle_mode": 1
      }
    }
  },
  {
    "name": "pvp.match_finished",
    "group": "PVP 与攻坚",
    "title": "PVP 终局冻结",
    "description": "PVP 权威终局结果已冻结。",
    "timing": "权威结果冻结后、奖励持久化前，每场一次。",
    "caveats": [
      "不是奖励事务收据；不要根据此事件另发奖励。",
      "winner_seat=255 表示 draw=true，不是角色 ID。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "终局发布路径关联角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "房间 ID。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "终局时成员快照。"
      },
      {
        "name": "details.winner_seat",
        "type": "integer",
        "description": "胜者座位；255 为平局标记。"
      },
      {
        "name": "details.draw",
        "type": "boolean",
        "description": "是否平局。"
      },
      {
        "name": "details.battle_mode",
        "type": "integer",
        "description": "战斗模式编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "70",
      "member_ids": [
        "10001",
        "10002"
      ],
      "details": {
        "winner_seat": 0,
        "draw": false,
        "battle_mode": 1
      }
    }
  },
  {
    "name": "raid.created",
    "group": "PVP 与攻坚",
    "title": "新攻坚实例创建",
    "description": "新的攻坚对象与 owner 已挂接。",
    "timing": "新实例挂接后、绑定响应前。",
    "caveats": [
      "重连恢复不发布为新创建。",
      "创建不是开战、扣门票或通关。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "创建路径关联角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "RaidKey 的十进制字符串。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "攻坚当前角色名单。"
      },
      {
        "name": "details.instance_id",
        "type": "string",
        "description": "实例 uint64 标识字符串。"
      },
      {
        "name": "details.raid_mode",
        "type": "integer (uint8)",
        "description": "攻坚 owner 模式编号；当前 1 安徒恩、2 卢克、3 超时空，尚未绑定时可为 0。"
      },
      {
        "name": "details.single",
        "type": "boolean",
        "description": "是否单人模式。"
      },
      {
        "name": "details.phase",
        "type": "integer",
        "description": "当前生命周期阶段编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "80",
      "member_ids": [
        "10001"
      ],
      "details": {
        "instance_id": "900000000000002",
        "raid_mode": 0,
        "single": false,
        "phase": 0
      }
    }
  },
  {
    "name": "raid.started",
    "group": "PVP 与攻坚",
    "title": "攻坚首次开战",
    "description": "攻坚首次开始状态已经提交。",
    "timing": "持久化入场扣费后、首次开战状态提交后、响应前。",
    "caveats": [
      "每次首次开始一次；重复开战不重复发布。",
      "不表示阶段通关、掉落或奖励结算。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "开战路径关联角色。"
      },
      {
        "name": "group_id",
        "type": "string",
        "description": "RaidKey 字符串。"
      },
      {
        "name": "member_ids",
        "type": "string[] | nil",
        "description": "攻坚成员快照。"
      },
      {
        "name": "details.instance_id",
        "type": "string",
        "description": "实例 ID 字符串。"
      },
      {
        "name": "details.raid_mode",
        "type": "integer (uint8)",
        "description": "当前 1 安徒恩、2 卢克、3 超时空。"
      },
      {
        "name": "details.single",
        "type": "boolean",
        "description": "是否单人模式。"
      },
      {
        "name": "details.phase",
        "type": "integer",
        "description": "生命周期阶段编号。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "group_id": "80",
      "member_ids": [
        "10001",
        "10002"
      ],
      "details": {
        "instance_id": "900000000000002",
        "raid_mode": 1,
        "single": false,
        "phase": 1
      }
    }
  },
  {
    "name": "chat.message.received",
    "group": "聊天与好友",
    "title": "聊天请求进入策略",
    "description": "结构合法且关联已选角色的聊天请求到达路由策略。",
    "timing": "转发和喇叭消耗前。",
    "caveats": [
      "此时 recipients=0；收到请求不代表随后允许或转发。",
      "通知不能阻断聊天；用 chat.message Hook 返回决策。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "发言角色。"
      },
      {
        "name": "mode",
        "type": "integer (uint8)",
        "description": "原生聊天模式编号。"
      },
      {
        "name": "text",
        "type": "string",
        "description": "GBK 解码后的正文快照。"
      },
      {
        "name": "item_links",
        "type": "integer",
        "description": "请求中物品链接计数，不含链接内容。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "进入策略的路径，当前有 town / peer。"
      },
      {
        "name": "recipients",
        "type": "integer",
        "description": "接收阶段为 0。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "mode": 0,
      "text": "大家好",
      "item_links": 0,
      "source": "town",
      "recipients": 0
    }
  },
  {
    "name": "chat.message.blocked",
    "group": "聊天与好友",
    "title": "聊天被插件策略拒绝",
    "description": "chat.message 业务 Hook 决策拒绝该请求。",
    "timing": "策略拒绝后、任何转发或喇叭消耗前。",
    "caveats": [
      "不是所有核心聊天失败的汇总；脚本错误回退原规则时也不等于 blocked。",
      "recipients=0；正文只用于观察。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "请求发言角色。"
      },
      {
        "name": "mode",
        "type": "integer (uint8)",
        "description": "聊天模式编号。"
      },
      {
        "name": "text",
        "type": "string",
        "description": "解码正文快照。"
      },
      {
        "name": "item_links",
        "type": "integer",
        "description": "物品链接数。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "策略输入路径标识。"
      },
      {
        "name": "recipients",
        "type": "integer",
        "description": "此阶段为 0。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "mode": 0,
      "text": "示例被拒绝文字",
      "item_links": 0,
      "source": "town",
      "recipients": 0
    }
  },
  {
    "name": "chat.message.forwarded",
    "group": "聊天与好友",
    "title": "聊天转发已尝试",
    "description": "宿主已尝试进行聊天转发。",
    "timing": "对应路由执行转发尝试后。",
    "caveats": [
      "recipients 是宿主接受数，不是客户端确认或实际阅读人数。",
      "source 在该阶段可为具体路由范围，与 received 的入口标识不同。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "发言角色。"
      },
      {
        "name": "mode",
        "type": "integer (uint8)",
        "description": "聊天模式编号。"
      },
      {
        "name": "text",
        "type": "string",
        "description": "解码正文。"
      },
      {
        "name": "item_links",
        "type": "integer",
        "description": "请求链接数。"
      },
      {
        "name": "source",
        "type": "string",
        "description": "实际路由来源/范围标识，例如 peer、whisper 或广播路径范围。"
      },
      {
        "name": "recipients",
        "type": "integer",
        "description": "宿主受理转发的数量。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "mode": 0,
      "text": "大家好",
      "item_links": 0,
      "source": "peer",
      "recipients": 1
    }
  },
  {
    "name": "friend.added",
    "group": "聊天与好友",
    "title": "好友添加被接受",
    "description": "好友 owner 已成功应用添加操作。",
    "timing": "好友 owner 成功返回后、成功响应前。",
    "caveats": [
      "可能包含已有状态的成功无操作，不能推断每次新增了一条关系。",
      "不提供账号或好友列表。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "peer_id",
        "type": "string | nil",
        "description": "解析出的好友角色 ID，空值省略。"
      },
      {
        "name": "peer_name",
        "type": "string",
        "description": "好友角色名称。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "peer_id": "10002",
      "peer_name": "示例好友"
    }
  },
  {
    "name": "friend.removed",
    "group": "聊天与好友",
    "title": "好友删除被接受",
    "description": "好友 owner 已成功应用移除操作。",
    "timing": "好友 owner 成功返回后、成功响应前。",
    "caveats": [
      "可含成功无操作；当前删除路径没有 peer_id，只提供目标名称。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "操作角色。"
      },
      {
        "name": "peer_id",
        "type": "string | nil",
        "description": "当前删除路径省略，应允许 nil。"
      },
      {
        "name": "peer_name",
        "type": "string",
        "description": "请求删除的好友名称。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "peer_name": "示例好友"
    }
  },
  {
    "name": "activity.reward_claimed",
    "group": "活动",
    "title": "活动新奖励提交",
    "description": "已接入的活动 owner 返回了本次新提交奖励。",
    "timing": "新 MailIDs 产生或旧 onlineevent 非重放领取成功后。",
    "caveats": [
      "收据重放、未获新奖励的请求不当作新领奖。",
      "覆盖 attendance_marble、beast_soul、monthly_attendance、weekly_attendance、legacy_levelup、level_aiming、online_pcroom_timepoint 和旧 onlineevent 的 EventID/StageID。",
      "旧 onlineevent 可直接发放，mail_count 可为 0；脱离会话的 owner 使 channel_id=0，不能直接频道公告。",
      "通知不具备可靠发奖保证，不能据此再次发放同一奖励。"
    ],
    "fields": [
      {
        "name": "character",
        "type": "Character",
        "description": "领奖角色；无会话时 channel_id=0。"
      },
      {
        "name": "activity",
        "type": "string",
        "description": "活动来源标识，或旧 onlineevent 的 EventID。"
      },
      {
        "name": "stage",
        "type": "string",
        "description": "来源对应阶段：位置、档位、累计天数、目标等级、daily:N,period:N 或 StageID。"
      },
      {
        "name": "mail_count",
        "type": "integer",
        "description": "本次新奖励邮件条数；直接发放可能 0。"
      }
    ],
    "example": {
      "character": {
        "id": "10001",
        "channel_id": 1
      },
      "activity": "monthly_attendance",
      "stage": "3",
      "mail_count": 1
    }
  }
]