实装与对抗训练实测报告 部分链路已验证,页面闭环受限

编排 UI · 默认教学入口 · 正式教学 API

编排与 API 已验证,教学页面闭环受限。需完成默认教学页面与正式任务运行的接线,才能从页面走完新模型对应的训练。

2026-09-05 · http://127.0.0.1:6180

证据组 2/2 已完成;检查通过 26,受限 2,失败 0,待验证 0;已校验截图 25 张。

资料 → 产品原型 → 设计 → 开发

1 · 资料

  • 实际查看《维修训练内容设计.pdf》第 1–3、5–6 页扫描件。第 1–2 页将虚拟、混合现实、AI 指导下的实装组织为递进训练,流程包含构建场景、编排任务、组班下发、学员训练与数据报告。
  • 本次使用狐狸与牛奶卡车测试素材验证软件链路,不将其视为原文装备维修内容或真实维修能力考核。原文已查看页面没有单列红蓝对抗规则;对抗依据现有教学实施、渠道合同、命令幂等及步骤事实文档验证。
  • 合同来源:unreal_tran_api/wiki/14-教学实施模块.md、19-训练定义渠道合同.md、20-教学命令幂等.md、21-教学步骤运行事实.md。

2 · 产品原型

  • 沿用现有训练编排工作台与模式配置表单,分别建立实装和对抗内容;保存、发布后重新打开检查步骤、分值、封面与模式参数。
  • 实装默认运行入口为离线识别回放;对抗默认入口为本地工作台。分别记录界面实际行为,再通过正式 API 验证服务端教学闭环。

3 · 设计

  • 实装配置三步人工确认,分值 30 / 30 / 40;完成进度按步骤推导为 33 / 67 / 100。验证失败重试、顺序约束、事件身份及重复事件处理。
  • 对抗配置红蓝两队、每队两人,步骤和提交均由 COMMANDER 执行;OPERATOR 用于岗位拒绝测试。验证同队共享运行、跨队隔离、服务器时限、提交与教员评定。
  • 任务固定引用已发布训练版本;只创建本次开发测试数据。人工确认和客户端模拟参数均明确标识为测试,不连接真实工位、PLC、摄像头或视觉服务。

4 · 开发

  • 修复模式配置被旧channelProfiles覆盖,保持默认profile与modeConfig一致;对抗分钟/秒及旧roundDuration兼容。
  • 保留显式空配置文本;每队人数范围与服务端1–200一致,无效数字阻止发布,不静默夹断。
  • 保留步骤设备事件、人工确认、岗位与运行编码;增删排序后重新计算严格递增进度。
  • 修复复制步骤编码冲突(含大小写),复制动作岗位映射随新动作编码迁移。
  • 显式清空allowedPositions不再补回默认三岗位,保持权限边界并交由正式发布校验阻断。
  • 修复instruction/summary双界面操作说明丢失及显式空提示恢复演示内容;用户实际编辑时同步。
  • 正式targetId优先,目标选择同步语义引用、节点与动作,防止旧targetRef把新目标回退。
  • 沿用上轮训练3D视口截图方案:受控TRAINING_COVER上传、同次保存资产与内容,保存/发布后列表正确显示截图。
  • 本次均为正式工程合同适配与bugfix,未新增数据库字段、执行DDL或更改原型业务流程;测试数据通过开发API创建。

两种模式的验证边界

模式正式渠道本轮 API 验证方法必检项默认界面边界
实装实训PHYSICAL正式 API 的 MANUAL 人工事件三步顺序、失败重试、来源权限、事件幂等、提交与评定默认离线识别页;设备 / 视觉接入另行联调
对抗训练CONFRONTATION正式 API 的红蓝两队共享运行岗位权限、两队隔离、顺序、时限、命令幂等、提交与评定默认本地工作台;不混同正式 API 运行

保留开发测试数据

训练 ID名称模式状态当前发布版本API 已测版本步骤数
163实测训练-牛奶卡车实装检查-20260905PHYSICALPUBLISHED2172153
164实测训练-狐狸红蓝协同巡检-20260905CONFRONTATIONPUBLISHED2162162

训练 163:API任务50固定215;说明字段兼容修复后在217做UI及封面回归,未改写任务快照。

训练 163 · 发布与配置记录
{
  "id": "163",
  "name": "实测训练-牛奶卡车实装检查-20260905",
  "mode": "PHYSICAL",
  "status": "PUBLISHED",
  "currentVersionId": "217",
  "publishedVersionId": "217",
  "sceneProjectId": "159",
  "sceneVersionId": "209",
  "stepCount": 3,
  "totalScore": 100,
  "cover": {
    "assetId": "2111",
    "image": "screenshots/physical-final-cover.jpg"
  },
  "trainingMode": "PHYSICAL",
  "modeConfig": {
    "type": "PHYSICAL",
    "stationName": "牛奶卡车测试工位 A",
    "equipmentCode": "E2E-TRUCK-163",
    "gatewayProtocol": "HTTP 测试网关",
    "sensorChannels": "人工外观确认;测试状态点位",
    "safetyInterlocks": "测试工位隔离确认"
  },
  "steps": [
    {
      "stepCode": "PHYSICAL-S01",
      "actionCode": "PHYSICAL-A01",
      "title": "核对卡车工位与装备",
      "summary": "核对测试工位与牛奶卡车编号。",
      "targetId": "scene:OBJ-1788605199171-2",
      "allowedPositions": [],
      "physicalEventRule": {
        "source": "MANUAL",
        "eventType": "step.physical-s01.confirmed",
        "progressPercent": 33,
        "manualConfirmAllowed": true
      },
      "score": 30
    },
    {
      "stepCode": "PHYSICAL-S02",
      "actionCode": "PHYSICAL-A02",
      "title": "检查卡车外观状态",
      "summary": "人工确认卡车外观状态,使用受控事件记录检查。",
      "targetId": "scene:OBJ-1788605199171-2",
      "allowedPositions": [],
      "physicalEventRule": {
        "source": "MANUAL",
        "eventType": "step.physical-s02.confirmed",
        "progressPercent": 67,
        "manualConfirmAllowed": true
      },
      "score": 30
    },
    {
      "stepCode": "PHYSICAL-S03",
      "actionCode": "PHYSICAL-A03",
      "title": "确认检查完成",
      "summary": "核实步骤记录并提交检查结果。",
      "targetId": "scene:OBJ-1788605199171-2",
      "allowedPositions": [],
      "physicalEventRule": {
        "source": "MANUAL",
        "eventType": "step.physical-s03.confirmed",
        "progressPercent": 100,
        "manualConfirmAllowed": true
      },
      "score": 40
    }
  ],
  "apiTestVersionId": "215",
  "apiVersionNote": "API任务50固定215;说明字段兼容修复后在217做UI及封面回归,未改写任务快照。"
}
训练 164 · 发布与配置记录
{
  "id": "164",
  "name": "实测训练-狐狸红蓝协同巡检-20260905",
  "mode": "CONFRONTATION",
  "status": "PUBLISHED",
  "currentVersionId": "216",
  "publishedVersionId": "216",
  "sceneProjectId": "160",
  "sceneVersionId": "210",
  "stepCount": 2,
  "totalScore": 100,
  "cover": {
    "assetId": "2108",
    "image": "screenshots/confrontation-final-cover.jpg"
  },
  "trainingMode": "CONFRONTATION",
  "modeConfig": {
    "type": "CONFRONTATION",
    "redTeamName": "狐狸巡检红队",
    "blueTeamName": "狐狸巡检蓝队",
    "teamSize": 2,
    "roundDurationMinutes": 7,
    "objective": "两队分别完成狐狸模型巡检并确认状态",
    "winRule": "按已完成步骤与协同检查结果评分",
    "submitPositions": [
      "COMMANDER"
    ],
    "roundDuration": 7,
    "eventInjections": ""
  },
  "steps": [
    {
      "stepCode": "CONFRONTATION-S01",
      "actionCode": "CONFRONTATION-A01",
      "title": "识别狐狸巡检目标",
      "summary": "红蓝两队分别识别场景中的狐狸模型,由指挥员确认目标。",
      "targetId": "scene:OBJ-1788605916565-6",
      "allowedPositions": [
        "COMMANDER"
      ],
      "physicalEventRule": {},
      "score": 50
    },
    {
      "stepCode": "CONFRONTATION-S02",
      "actionCode": "CONFRONTATION-A02",
      "title": "完成狐狸状态检查",
      "summary": "由指挥员完成状态确认,操作员协同观察;提交团队检查结果。",
      "targetId": "scene:OBJ-1788605916565-6",
      "allowedPositions": [
        "COMMANDER"
      ],
      "physicalEventRule": {},
      "score": 50
    }
  ],
  "apiTestVersionId": "216"
}

正式教学任务与运行

任务 ID运行 ID渠道队伍状态完成度评定分
5044PHYSICALNEUTRALREVIEWED100100
5145CONFRONTATIONREDREVIEWED100100
5146CONFRONTATIONBLUEREVIEWED100100
本次新增数据 ID
{
  "assignments": [
    "50",
    "51"
  ],
  "runs": [
    "44",
    "45",
    "46"
  ],
  "users": [
    "95",
    "96",
    "97",
    "98"
  ],
  "note": "仅新建本次开发测试数据,未修改或删除既有账号、任务与运行。"
}

随机测试密码与登录会话不写入报告;保留新建数据用于追溯。

5 · 测试

证据组 2/2 已完成;检查通过 26,受限 2,失败 0,待验证 0;已校验截图 25 张。

实装实训与对抗训练真实流程测试 部分链路已验证,页面闭环受限

证据类型:UI · evidence.json

实装:创建、绑定牛奶卡车、3步配置、保存重开与发布 通过

查看脱敏详细记录
{
  "title": "实装:创建、绑定牛奶卡车、3步配置、保存重开与发布",
  "status": "PASS",
  "screenshots": [
    "screenshots/physical-settings-reopen.png",
    "screenshots/physical-authoring.png",
    "screenshots/physical-preflight.png",
    "screenshots/physical-published.png"
  ],
  "details": {
    "id": "163",
    "version": "215",
    "progress": [
      33,
      67,
      100
    ],
    "profile": {
      "type": "PHYSICAL",
      "stationName": "牛奶卡车测试工位 A",
      "equipmentCode": "E2E-TRUCK-163",
      "gatewayProtocol": "HTTP 测试网关",
      "sensorChannels": "人工外观确认;测试状态点位",
      "safetyInterlocks": "测试工位隔离确认"
    }
  }
}

对抗:每队人数为小数时阻止发布 通过

查看脱敏详细记录
{
  "title": "对抗:每队人数为小数时阻止发布",
  "status": "PASS",
  "screenshots": [
    "screenshots/confrontation-invalid-team-size.png"
  ],
  "details": {
    "input": 2.5,
    "message": "发布校验未通过\n×\n发现 1 个必须处理的问题\n\n2 个步骤 · 1 个目标 · 0 个故障 · 及格线 80 分\n\n!\n每队人数必须是 1 到 200 的整数\nmodeConfig.teamSize\ni\n本步骤尚未配置必选安全前置条件\nsteps[0].safetyRules\ni\n本步骤尚未配置必选安全前置条件\nsteps[1].safetyRules\ni\n尚未绑定离线讲解文件,运行时将保留字幕并使用默认本地语音\nsteps.audio\n关闭"
  }
}

对抗:显式清空岗位后保存重开,不恢复默认授权 通过

查看脱敏详细记录
{
  "title": "对抗:显式清空岗位后保存重开,不恢复默认授权",
  "status": "PASS",
  "screenshots": [
    "screenshots/confrontation-empty-positions.png"
  ],
  "details": {
    "allowedPositions": [],
    "published": false
  }
}

对抗:狐狸场景、两步巡检、岗位配置、说明往返与发布 通过

查看脱敏详细记录
{
  "title": "对抗:狐狸场景、两步巡检、岗位配置、说明往返与发布",
  "status": "PASS",
  "screenshots": [
    "screenshots/confrontation-positions.png",
    "screenshots/confrontation-settings-reopen.png",
    "screenshots/confrontation-authoring.png",
    "screenshots/confrontation-preflight.png",
    "screenshots/confrontation-published.png"
  ],
  "details": {
    "id": "164",
    "version": "216",
    "profile": {
      "type": "CONFRONTATION",
      "redTeamName": "狐狸巡检红队",
      "blueTeamName": "狐狸巡检蓝队",
      "teamSize": 2,
      "roundDurationMinutes": 7,
      "objective": "两队分别完成狐狸模型巡检并确认状态",
      "winRule": "按已完成步骤与协同检查结果评分",
      "submitPositions": [
        "COMMANDER"
      ],
      "roundDuration": 7,
      "eventInjections": ""
    },
    "steps": [
      {
        "title": "识别狐狸巡检目标",
        "summary": "红蓝两队分别识别场景中的狐狸模型,由指挥员确认目标。",
        "allowedPositions": [
          "COMMANDER"
        ]
      },
      {
        "title": "完成狐狸状态检查",
        "summary": "由指挥员完成状态确认,操作员协同观察;提交团队检查结果。",
        "allowedPositions": [
          "COMMANDER"
        ]
      }
    ]
  }
}

实装:说明兼容修复回写,重新截图封面及发布 通过

查看脱敏详细记录
{
  "title": "实装:说明兼容修复回写,重新截图封面及发布",
  "status": "PASS",
  "screenshots": [
    "screenshots/physical-final-published.png"
  ],
  "details": {
    "projectId": "163",
    "publishedVersionId": "217",
    "apiTestVersionId": "215",
    "note": "既有任务50固定215;本次仅回填说明与更新截图封面,未改写任务快照。",
    "steps": [
      {
        "stepCode": "PHYSICAL-S01",
        "actionCode": "PHYSICAL-A01",
        "summary": "核对测试工位与牛奶卡车编号。",
        "physicalEventRule": {
          "source": "MANUAL",
          "eventType": "step.physical-s01.confirmed",
          "progressPercent": 33,
          "manualConfirmAllowed": true
        }
      },
      {
        "stepCode": "PHYSICAL-S02",
        "actionCode": "PHYSICAL-A02",
        "summary": "人工确认卡车外观状态,使用受控事件记录检查。",
        "physicalEventRule": {
          "source": "MANUAL",
          "eventType": "step.physical-s02.confirmed",
          "progressPercent": 67,
          "manualConfirmAllowed": true
        }
      },
      {
        "stepCode": "PHYSICAL-S03",
        "actionCode": "PHYSICAL-A03",
        "summary": "核实步骤记录并提交检查结果。",
        "physicalEventRule": {
          "source": "MANUAL",
          "eventType": "step.physical-s03.confirmed",
          "progressPercent": 100,
          "manualConfirmAllowed": true
        }
      }
    ]
  }
}

实装默认页面:离线播放与候选复核可操作,无法执行新卡车正式步骤 受限(需功能接线)

查看脱敏详细记录
{
  "title": "实装默认页面:离线播放与候选复核可操作,无法执行新卡车正式步骤",
  "status": "BLOCKED",
  "screenshots": [
    "screenshots/physical-teaching-list.png",
    "screenshots/physical-offline-preview.png",
    "screenshots/physical-offline-confirmed.png"
  ],
  "details": {
    "assignmentId": "50",
    "previewUrl": "/teaching/physical-training/preview/50",
    "observed": "进入任务后仍显示固定45秒维修识别录像,确认只改变本次页面候选,未加载卡车三步正式运行。",
    "businessWrites": [],
    "required": "需将正式任务快照、场景、人工/设备事件及运行记录接入工作台。"
  }
}

对抗默认页面:新建下拉仅有本地液压预设,无法选择已发布狐狸训练 受限(需功能接线)

查看脱敏详细记录
{
  "title": "对抗默认页面:新建下拉仅有本地液压预设,无法选择已发布狐狸训练",
  "status": "BLOCKED",
  "screenshots": [
    "screenshots/confrontation-final-entry.png",
    "screenshots/confrontation-final-local-create.png"
  ],
  "details": {
    "options": [
      "桥梁架设装备液压系统检测与维修训练"
    ],
    "formalAssignmentId": "51",
    "formalAssignmentExists": true,
    "required": "需将默认任务清单、创建表单和执行入口接入正式对抗任务服务,并确认通用巡检与五阶段排故的适用范围。"
  }
}

训练列表两种模式展示各自真实截图封面 通过

查看脱敏详细记录
{
  "title": "训练列表两种模式展示各自真实截图封面",
  "status": "PASS",
  "screenshots": [
    "screenshots/physical-list-cover.png",
    "screenshots/confrontation-list-cover.png"
  ],
  "details": {
    "projects": [
      "163",
      "164"
    ],
    "authenticatedImagesLoaded": true
  }
}

牛奶卡车实装检查:发布重开、模型实际可见、截图封面 通过

查看脱敏详细记录
{
  "title": "牛奶卡车实装检查:发布重开、模型实际可见、截图封面",
  "status": "PASS",
  "screenshots": [
    "screenshots/physical-independent-reopen.png",
    "screenshots/physical-independent-settings.png",
    "screenshots/physical-final-cover.jpg"
  ],
  "details": {
    "state": "ready",
    "meshes": 5,
    "visibleMeshes": 5,
    "skinnedMeshes": 0,
    "position": [
      4.2,
      0.20617168998977797,
      -0.4356763541543951
    ],
    "scale": [
      1.2323086149245381,
      1.2323086149245381,
      1.2323086149245381
    ],
    "finiteBounds": true,
    "size": [
      3.4406057210321332,
      3.390913184034896,
      6.000000000000001
    ],
    "camera": {
      "position": [
        10.565439077211714,
        5.0456876852867705,
        7.37050840519251
      ],
      "target": [
        4.2,
        1.695456592017448,
        0
      ]
    },
    "sample": {
      "width": 320,
      "height": 180,
      "changedPixels": 11669
    },
    "scene": {
      "projectId": "159",
      "versionId": "209"
    },
    "targets": [
      {
        "id": "scene:OBJ-1788605199171-2",
        "name": "牛奶卡车检验主装备",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-1ba581e6",
        "name": "Yup2Zup",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-004dec41",
        "name": "Cesium_Milk_Truck",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-5f7e4bee",
        "name": "Cesium_Milk_Truck_1",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-607e4d81",
        "name": "Cesium_Milk_Truck_2",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-5d7e48c8",
        "name": "Cesium_Milk_Truck_3",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-5e7e4a5b",
        "name": "Node",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-ce2feac4",
        "name": "Wheels",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-637e523a",
        "name": "Node001",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605199171-2/part/interaction-f417f82d",
        "name": "Wheels001",
        "source": "scene"
      }
    ],
    "steps": [
      {
        "title": "核对卡车工位与装备",
        "targetId": "scene:OBJ-1788605199171-2",
        "weight": 30
      },
      {
        "title": "检查卡车外观状态",
        "targetId": "scene:OBJ-1788605199171-2",
        "weight": 30
      },
      {
        "title": "确认检查完成",
        "targetId": "scene:OBJ-1788605199171-2",
        "weight": 40
      }
    ],
    "cover": {
      "assetId": "2111",
      "bytes": 42163,
      "sha256": "efb7060464f840bde78744d89567c609dc7b7922216d1c948fe22c1eed3d41a4",
      "width": 628,
      "height": 640
    },
    "pageErrors": [],
    "blockedWrites": []
  }
}

狐狸红蓝协同巡检:发布重开、模型实际可见、截图封面 通过

查看脱敏详细记录
{
  "title": "狐狸红蓝协同巡检:发布重开、模型实际可见、截图封面",
  "status": "PASS",
  "screenshots": [
    "screenshots/confrontation-independent-reopen.png",
    "screenshots/confrontation-independent-settings.png",
    "screenshots/confrontation-final-cover.jpg"
  ],
  "details": {
    "state": "ready",
    "meshes": 1,
    "visibleMeshes": 1,
    "skinnedMeshes": 1,
    "position": [
      -7.5,
      0.10930174852949677,
      0.3440109341705351
    ],
    "scale": [
      0.03616375932570189,
      0.03616375932570189,
      0.03616375932570189
    ],
    "finiteBounds": true,
    "size": [
      0.9658796100519353,
      2.811899945787403,
      6
    ],
    "camera": {
      "position": [
        -0.04179225073787585,
        6.099634646023559,
        17.355036987378313
      ],
      "target": [
        -7.512232860974557,
        1.4059499759307126,
        -2.2204460492503126e-16
      ]
    },
    "sample": {
      "width": 320,
      "height": 180,
      "changedPixels": 827
    },
    "scene": {
      "projectId": "160",
      "versionId": "210"
    },
    "targets": [
      {
        "id": "scene:OBJ-1788605873329-2",
        "name": "维修装备主体 02",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605916565-6",
        "name": "狐狸野外巡检目标",
        "source": "scene"
      },
      {
        "id": "scene:OBJ-1788605916565-6/part/interaction-a3d35c26",
        "name": "fox",
        "source": "scene"
      }
    ],
    "steps": [
      {
        "title": "识别狐狸巡检目标",
        "targetId": "scene:OBJ-1788605916565-6",
        "weight": 50
      },
      {
        "title": "完成狐狸状态检查",
        "targetId": "scene:OBJ-1788605916565-6",
        "weight": 50
      }
    ],
    "cover": {
      "assetId": "2108",
      "bytes": 51257,
      "sha256": "79779a9d1e40c0c160fa3dab25e83931639942f53e2ee3a5da12f9f86ad70081",
      "width": 628,
      "height": 640
    },
    "pageErrors": [],
    "blockedWrites": []
  }
}
evidence.json · 完整记录
{
  "title": "实装实训与对抗训练真实流程测试",
  "startedAt": "2026-09-05T15:37:32.805Z",
  "status": "PASS_WITH_LIMITATIONS",
  "checks": [
    {
      "title": "实装:创建、绑定牛奶卡车、3步配置、保存重开与发布",
      "status": "PASS",
      "screenshots": [
        "screenshots/physical-settings-reopen.png",
        "screenshots/physical-authoring.png",
        "screenshots/physical-preflight.png",
        "screenshots/physical-published.png"
      ],
      "details": {
        "id": "163",
        "version": "215",
        "progress": [
          33,
          67,
          100
        ],
        "profile": {
          "type": "PHYSICAL",
          "stationName": "牛奶卡车测试工位 A",
          "equipmentCode": "E2E-TRUCK-163",
          "gatewayProtocol": "HTTP 测试网关",
          "sensorChannels": "人工外观确认;测试状态点位",
          "safetyInterlocks": "测试工位隔离确认"
        }
      }
    },
    {
      "title": "对抗:每队人数为小数时阻止发布",
      "status": "PASS",
      "screenshots": [
        "screenshots/confrontation-invalid-team-size.png"
      ],
      "details": {
        "input": 2.5,
        "message": "发布校验未通过\n×\n发现 1 个必须处理的问题\n\n2 个步骤 · 1 个目标 · 0 个故障 · 及格线 80 分\n\n!\n每队人数必须是 1 到 200 的整数\nmodeConfig.teamSize\ni\n本步骤尚未配置必选安全前置条件\nsteps[0].safetyRules\ni\n本步骤尚未配置必选安全前置条件\nsteps[1].safetyRules\ni\n尚未绑定离线讲解文件,运行时将保留字幕并使用默认本地语音\nsteps.audio\n关闭"
      }
    },
    {
      "title": "对抗:显式清空岗位后保存重开,不恢复默认授权",
      "status": "PASS",
      "screenshots": [
        "screenshots/confrontation-empty-positions.png"
      ],
      "details": {
        "allowedPositions": [],
        "published": false
      }
    },
    {
      "title": "对抗:狐狸场景、两步巡检、岗位配置、说明往返与发布",
      "status": "PASS",
      "screenshots": [
        "screenshots/confrontation-positions.png",
        "screenshots/confrontation-settings-reopen.png",
        "screenshots/confrontation-authoring.png",
        "screenshots/confrontation-preflight.png",
        "screenshots/confrontation-published.png"
      ],
      "details": {
        "id": "164",
        "version": "216",
        "profile": {
          "type": "CONFRONTATION",
          "redTeamName": "狐狸巡检红队",
          "blueTeamName": "狐狸巡检蓝队",
          "teamSize": 2,
          "roundDurationMinutes": 7,
          "objective": "两队分别完成狐狸模型巡检并确认状态",
          "winRule": "按已完成步骤与协同检查结果评分",
          "submitPositions": [
            "COMMANDER"
          ],
          "roundDuration": 7,
          "eventInjections": ""
        },
        "steps": [
          {
            "title": "识别狐狸巡检目标",
            "summary": "红蓝两队分别识别场景中的狐狸模型,由指挥员确认目标。",
            "allowedPositions": [
              "COMMANDER"
            ]
          },
          {
            "title": "完成狐狸状态检查",
            "summary": "由指挥员完成状态确认,操作员协同观察;提交团队检查结果。",
            "allowedPositions": [
              "COMMANDER"
            ]
          }
        ]
      }
    },
    {
      "title": "实装:说明兼容修复回写,重新截图封面及发布",
      "status": "PASS",
      "screenshots": [
        "screenshots/physical-final-published.png"
      ],
      "details": {
        "projectId": "163",
        "publishedVersionId": "217",
        "apiTestVersionId": "215",
        "note": "既有任务50固定215;本次仅回填说明与更新截图封面,未改写任务快照。",
        "steps": [
          {
            "stepCode": "PHYSICAL-S01",
            "actionCode": "PHYSICAL-A01",
            "summary": "核对测试工位与牛奶卡车编号。",
            "physicalEventRule": {
              "source": "MANUAL",
              "eventType": "step.physical-s01.confirmed",
              "progressPercent": 33,
              "manualConfirmAllowed": true
            }
          },
          {
            "stepCode": "PHYSICAL-S02",
            "actionCode": "PHYSICAL-A02",
            "summary": "人工确认卡车外观状态,使用受控事件记录检查。",
            "physicalEventRule": {
              "source": "MANUAL",
              "eventType": "step.physical-s02.confirmed",
              "progressPercent": 67,
              "manualConfirmAllowed": true
            }
          },
          {
            "stepCode": "PHYSICAL-S03",
            "actionCode": "PHYSICAL-A03",
            "summary": "核实步骤记录并提交检查结果。",
            "physicalEventRule": {
              "source": "MANUAL",
              "eventType": "step.physical-s03.confirmed",
              "progressPercent": 100,
              "manualConfirmAllowed": true
            }
          }
        ]
      }
    },
    {
      "title": "实装默认页面:离线播放与候选复核可操作,无法执行新卡车正式步骤",
      "status": "BLOCKED",
      "screenshots": [
        "screenshots/physical-teaching-list.png",
        "screenshots/physical-offline-preview.png",
        "screenshots/physical-offline-confirmed.png"
      ],
      "details": {
        "assignmentId": "50",
        "previewUrl": "/teaching/physical-training/preview/50",
        "observed": "进入任务后仍显示固定45秒维修识别录像,确认只改变本次页面候选,未加载卡车三步正式运行。",
        "businessWrites": [],
        "required": "需将正式任务快照、场景、人工/设备事件及运行记录接入工作台。"
      }
    },
    {
      "title": "对抗默认页面:新建下拉仅有本地液压预设,无法选择已发布狐狸训练",
      "status": "BLOCKED",
      "screenshots": [
        "screenshots/confrontation-final-entry.png",
        "screenshots/confrontation-final-local-create.png"
      ],
      "details": {
        "options": [
          "桥梁架设装备液压系统检测与维修训练"
        ],
        "formalAssignmentId": "51",
        "formalAssignmentExists": true,
        "required": "需将默认任务清单、创建表单和执行入口接入正式对抗任务服务,并确认通用巡检与五阶段排故的适用范围。"
      }
    },
    {
      "title": "训练列表两种模式展示各自真实截图封面",
      "status": "PASS",
      "screenshots": [
        "screenshots/physical-list-cover.png",
        "screenshots/confrontation-list-cover.png"
      ],
      "details": {
        "projects": [
          "163",
          "164"
        ],
        "authenticatedImagesLoaded": true
      }
    },
    {
      "title": "牛奶卡车实装检查:发布重开、模型实际可见、截图封面",
      "status": "PASS",
      "screenshots": [
        "screenshots/physical-independent-reopen.png",
        "screenshots/physical-independent-settings.png",
        "screenshots/physical-final-cover.jpg"
      ],
      "details": {
        "state": "ready",
        "meshes": 5,
        "visibleMeshes": 5,
        "skinnedMeshes": 0,
        "position": [
          4.2,
          0.20617168998977797,
          -0.4356763541543951
        ],
        "scale": [
          1.2323086149245381,
          1.2323086149245381,
          1.2323086149245381
        ],
        "finiteBounds": true,
        "size": [
          3.4406057210321332,
          3.390913184034896,
          6.000000000000001
        ],
        "camera": {
          "position": [
            10.565439077211714,
            5.0456876852867705,
            7.37050840519251
          ],
          "target": [
            4.2,
            1.695456592017448,
            0
          ]
        },
        "sample": {
          "width": 320,
          "height": 180,
          "changedPixels": 11669
        },
        "scene": {
          "projectId": "159",
          "versionId": "209"
        },
        "targets": [
          {
            "id": "scene:OBJ-1788605199171-2",
            "name": "牛奶卡车检验主装备",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-1ba581e6",
            "name": "Yup2Zup",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-004dec41",
            "name": "Cesium_Milk_Truck",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-5f7e4bee",
            "name": "Cesium_Milk_Truck_1",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-607e4d81",
            "name": "Cesium_Milk_Truck_2",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-5d7e48c8",
            "name": "Cesium_Milk_Truck_3",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-5e7e4a5b",
            "name": "Node",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-ce2feac4",
            "name": "Wheels",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-637e523a",
            "name": "Node001",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605199171-2/part/interaction-f417f82d",
            "name": "Wheels001",
            "source": "scene"
          }
        ],
        "steps": [
          {
            "title": "核对卡车工位与装备",
            "targetId": "scene:OBJ-1788605199171-2",
            "weight": 30
          },
          {
            "title": "检查卡车外观状态",
            "targetId": "scene:OBJ-1788605199171-2",
            "weight": 30
          },
          {
            "title": "确认检查完成",
            "targetId": "scene:OBJ-1788605199171-2",
            "weight": 40
          }
        ],
        "cover": {
          "assetId": "2111",
          "bytes": 42163,
          "sha256": "efb7060464f840bde78744d89567c609dc7b7922216d1c948fe22c1eed3d41a4",
          "width": 628,
          "height": 640
        },
        "pageErrors": [],
        "blockedWrites": []
      }
    },
    {
      "title": "狐狸红蓝协同巡检:发布重开、模型实际可见、截图封面",
      "status": "PASS",
      "screenshots": [
        "screenshots/confrontation-independent-reopen.png",
        "screenshots/confrontation-independent-settings.png",
        "screenshots/confrontation-final-cover.jpg"
      ],
      "details": {
        "state": "ready",
        "meshes": 1,
        "visibleMeshes": 1,
        "skinnedMeshes": 1,
        "position": [
          -7.5,
          0.10930174852949677,
          0.3440109341705351
        ],
        "scale": [
          0.03616375932570189,
          0.03616375932570189,
          0.03616375932570189
        ],
        "finiteBounds": true,
        "size": [
          0.9658796100519353,
          2.811899945787403,
          6
        ],
        "camera": {
          "position": [
            -0.04179225073787585,
            6.099634646023559,
            17.355036987378313
          ],
          "target": [
            -7.512232860974557,
            1.4059499759307126,
            -2.2204460492503126e-16
          ]
        },
        "sample": {
          "width": 320,
          "height": 180,
          "changedPixels": 827
        },
        "scene": {
          "projectId": "160",
          "versionId": "210"
        },
        "targets": [
          {
            "id": "scene:OBJ-1788605873329-2",
            "name": "维修装备主体 02",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605916565-6",
            "name": "狐狸野外巡检目标",
            "source": "scene"
          },
          {
            "id": "scene:OBJ-1788605916565-6/part/interaction-a3d35c26",
            "name": "fox",
            "source": "scene"
          }
        ],
        "steps": [
          {
            "title": "识别狐狸巡检目标",
            "targetId": "scene:OBJ-1788605916565-6",
            "weight": 50
          },
          {
            "title": "完成狐狸状态检查",
            "targetId": "scene:OBJ-1788605916565-6",
            "weight": 50
          }
        ],
        "cover": {
          "assetId": "2108",
          "bytes": 51257,
          "sha256": "79779a9d1e40c0c160fa3dab25e83931639942f53e2ee3a5da12f9f86ad70081",
          "width": 628,
          "height": 640
        },
        "pageErrors": [],
        "blockedWrites": []
      }
    }
  ],
  "projects": [
    {
      "id": "163",
      "name": "实测训练-牛奶卡车实装检查-20260905",
      "mode": "PHYSICAL",
      "status": "PUBLISHED",
      "currentVersionId": "217",
      "publishedVersionId": "217",
      "sceneProjectId": "159",
      "sceneVersionId": "209",
      "stepCount": 3,
      "totalScore": 100,
      "cover": {
        "assetId": "2111",
        "image": "screenshots/physical-final-cover.jpg"
      },
      "trainingMode": "PHYSICAL",
      "modeConfig": {
        "type": "PHYSICAL",
        "stationName": "牛奶卡车测试工位 A",
        "equipmentCode": "E2E-TRUCK-163",
        "gatewayProtocol": "HTTP 测试网关",
        "sensorChannels": "人工外观确认;测试状态点位",
        "safetyInterlocks": "测试工位隔离确认"
      },
      "steps": [
        {
          "stepCode": "PHYSICAL-S01",
          "actionCode": "PHYSICAL-A01",
          "title": "核对卡车工位与装备",
          "summary": "核对测试工位与牛奶卡车编号。",
          "targetId": "scene:OBJ-1788605199171-2",
          "allowedPositions": [],
          "physicalEventRule": {
            "source": "MANUAL",
            "eventType": "step.physical-s01.confirmed",
            "progressPercent": 33,
            "manualConfirmAllowed": true
          },
          "score": 30
        },
        {
          "stepCode": "PHYSICAL-S02",
          "actionCode": "PHYSICAL-A02",
          "title": "检查卡车外观状态",
          "summary": "人工确认卡车外观状态,使用受控事件记录检查。",
          "targetId": "scene:OBJ-1788605199171-2",
          "allowedPositions": [],
          "physicalEventRule": {
            "source": "MANUAL",
            "eventType": "step.physical-s02.confirmed",
            "progressPercent": 67,
            "manualConfirmAllowed": true
          },
          "score": 30
        },
        {
          "stepCode": "PHYSICAL-S03",
          "actionCode": "PHYSICAL-A03",
          "title": "确认检查完成",
          "summary": "核实步骤记录并提交检查结果。",
          "targetId": "scene:OBJ-1788605199171-2",
          "allowedPositions": [],
          "physicalEventRule": {
            "source": "MANUAL",
            "eventType": "step.physical-s03.confirmed",
            "progressPercent": 100,
            "manualConfirmAllowed": true
          },
          "score": 40
        }
      ],
      "apiTestVersionId": "215",
      "apiVersionNote": "API任务50固定215;说明字段兼容修复后在217做UI及封面回归,未改写任务快照。"
    },
    {
      "id": "164",
      "name": "实测训练-狐狸红蓝协同巡检-20260905",
      "mode": "CONFRONTATION",
      "status": "PUBLISHED",
      "currentVersionId": "216",
      "publishedVersionId": "216",
      "sceneProjectId": "160",
      "sceneVersionId": "210",
      "stepCount": 2,
      "totalScore": 100,
      "cover": {
        "assetId": "2108",
        "image": "screenshots/confrontation-final-cover.jpg"
      },
      "trainingMode": "CONFRONTATION",
      "modeConfig": {
        "type": "CONFRONTATION",
        "redTeamName": "狐狸巡检红队",
        "blueTeamName": "狐狸巡检蓝队",
        "teamSize": 2,
        "roundDurationMinutes": 7,
        "objective": "两队分别完成狐狸模型巡检并确认状态",
        "winRule": "按已完成步骤与协同检查结果评分",
        "submitPositions": [
          "COMMANDER"
        ],
        "roundDuration": 7,
        "eventInjections": ""
      },
      "steps": [
        {
          "stepCode": "CONFRONTATION-S01",
          "actionCode": "CONFRONTATION-A01",
          "title": "识别狐狸巡检目标",
          "summary": "红蓝两队分别识别场景中的狐狸模型,由指挥员确认目标。",
          "targetId": "scene:OBJ-1788605916565-6",
          "allowedPositions": [
            "COMMANDER"
          ],
          "physicalEventRule": {},
          "score": 50
        },
        {
          "stepCode": "CONFRONTATION-S02",
          "actionCode": "CONFRONTATION-A02",
          "title": "完成狐狸状态检查",
          "summary": "由指挥员完成状态确认,操作员协同观察;提交团队检查结果。",
          "targetId": "scene:OBJ-1788605916565-6",
          "allowedPositions": [
            "COMMANDER"
          ],
          "physicalEventRule": {},
          "score": 50
        }
      ],
      "apiTestVersionId": "216"
    }
  ],
  "bugs": [],
  "limitations": [
    "实装为MANUAL人工事件合同测试,没有接真实PLC、摄像头、视觉识别服务或安全联锁设备。",
    "两步狐狸巡检用于通用步骤与红蓝岗位合同,不是需要CONF-INSPECT等五个固定编码的完整排故作业;未宣称排故工作台阶段回写已打通。",
    "对抗验证服务端设置了7分钟截止时刻,未等待自然超时触发;未把API账号请求视为多人跨浏览器实时协同UI测试。",
    "牛奶卡车沿用原发布场景的视角,车间立柱遮挡部分车身;真实模型已渲染且封面来自该视口。",
    "实装当前发布217仅回填兼容说明并更新封面;已完成教学任务50仍固定不可变版本215。",
    "历史仅positionActions设置动作岗位的定义在教学读取侧与当前发布预检存在口径差异;本次按现有发布规则配置非空allowedPositions,未改后端岗位合同。",
    "开发环境列表切换曾出现一次15秒超时,刷新后恢复;独立复测两种模式共6次查询均HTTP 200、耗时247–403ms,未复现稳定慢查询。详见list-api-latency.json。"
  ],
  "pageErrors": [],
  "development": [
    "修复模式配置被旧channelProfiles覆盖,保持默认profile与modeConfig一致;对抗分钟/秒及旧roundDuration兼容。",
    "保留显式空配置文本;每队人数范围与服务端1–200一致,无效数字阻止发布,不静默夹断。",
    "保留步骤设备事件、人工确认、岗位与运行编码;增删排序后重新计算严格递增进度。",
    "修复复制步骤编码冲突(含大小写),复制动作岗位映射随新动作编码迁移。",
    "显式清空allowedPositions不再补回默认三岗位,保持权限边界并交由正式发布校验阻断。",
    "修复instruction/summary双界面操作说明丢失及显式空提示恢复演示内容;用户实际编辑时同步。",
    "正式targetId优先,目标选择同步语义引用、节点与动作,防止旧targetRef把新目标回退。",
    "沿用上轮训练3D视口截图方案:受控TRAINING_COVER上传、同次保存资产与内容,保存/发布后列表正确显示截图。",
    "本次均为正式工程合同适配与bugfix,未新增数据库字段、执行DDL或更改原型业务流程;测试数据通过开发API创建。"
  ],
  "commands": [
    {
      "command": "pnpm run build",
      "status": "PASS",
      "details": "vue-tsc、Vite构建和legacy iframe分发校验均通过;仅已有包体积提示。"
    },
    {
      "command": "node --test tools/training-*.test.mjs(本次8个聚焦文件)",
      "status": "PASS",
      "details": "94/94通过,涵盖封面、场景、真实模型、目标、元数据、模式与步骤兼容。"
    },
    {
      "command": "pnpm run test:training-legacy",
      "status": "PASS",
      "details": "两项既有训练/地形合同检查通过。"
    },
    {
      "command": "content-training-studio.spec.ts / Edge",
      "status": "PASS",
      "details": "7/7通过(mock API的工作台回归),无跳过、无不稳定用例,独立报告studio-regression/html/index.html。"
    },
    {
      "command": "UTE2E_TRAINING_MODES=1 UTE2E_BASE_URL=http://192.168.31.168:6180 node tools/training-scene-visibility.e2e.mjs",
      "status": "PASS",
      "details": "独立Edge会话2/2通过,真实LAN服务、禁止业务写请求;模型可见像素差、固定场景依赖、JPEG尺寸与SHA-256全部通过。"
    },
    {
      "command": "node tools/training-modes-api-live.mjs(163:215;164:216)",
      "status": "PASS",
      "details": "18/18检查组通过,90次正式教学API请求;含训练/场景/模型固定快照只读复核,详见api-evidence.json。"
    }
  ],
  "confirmationItems": [
    "将实装工作台从固定离线识别回放扩展为读取正式任务、已发布场景和步骤,并接入人工/设备事件、提交与结果。",
    "将对抗默认入口从本地预设任务接入正式任务清单、创建和执行链路;确认通用巡检步骤与五阶段排故工作台的适用范围。"
  ],
  "finishedAt": "2026-09-05T15:58:39.239Z"
}

实装人工事件与红蓝对抗正式 API 闭环 通过

证据类型:API · api-evidence.json

开始命令重放不会重复激活或递增次数 通过

查看脱敏详细记录
{
  "title": "开始命令重放不会重复激活或递增次数",
  "status": "PASS",
  "details": {
    "runId": "44",
    "version": 2,
    "attemptCount": 1
  }
}

实装任务固定发布版本、分配学员并开始 通过

查看脱敏详细记录
{
  "title": "实装任务固定发布版本、分配学员并开始",
  "status": "PASS",
  "details": {
    "assignmentId": "50",
    "run": {
      "id": "44",
      "assignmentId": "50",
      "status": "IN_PROGRESS",
      "version": 2,
      "progressPercent": 0,
      "currentStepCode": "PHYSICAL-S01",
      "score": null,
      "passed": null
    },
    "content": {
      "projectId": "163",
      "versionId": "215"
    },
    "rules": [
      {
        "stepCode": "PHYSICAL-S01",
        "source": "MANUAL",
        "eventType": "step.physical-s01.confirmed",
        "progressPercent": 33
      },
      {
        "stepCode": "PHYSICAL-S02",
        "source": "MANUAL",
        "eventType": "step.physical-s02.confirmed",
        "progressPercent": 67
      },
      {
        "stepCode": "PHYSICAL-S03",
        "source": "MANUAL",
        "eventType": "step.physical-s03.confirmed",
        "progressPercent": 100
      }
    ]
  }
}

实装拒绝普通进度接口、抢跑、提前提交及错误事件身份 通过

查看脱敏详细记录
{
  "title": "实装拒绝普通进度接口、抢跑、提前提交及错误事件身份",
  "status": "PASS",
  "details": {
    "runId": "44",
    "forbiddenProgress": {
      "status": 403,
      "message": "实装运行只能由设备、视觉或人工确认事件推进"
    },
    "prematureSubmit": {
      "status": 409,
      "message": "训练步骤尚未全部完成,不能提交"
    },
    "skipped": {
      "status": 409,
      "message": "物理事件必须匹配当前待完成步骤,不能跳步或回退"
    },
    "untrustedDevice": {
      "status": 403,
      "message": "无权执行此操作"
    },
    "managerManual": {
      "status": 403,
      "message": "当前学员不是该运行成员"
    },
    "progressUnchanged": 0
  }
}

实装不匹配事件失败,必须重试后才可继续 通过

查看脱敏详细记录
{
  "title": "实装不匹配事件失败,必须重试后才可继续",
  "status": "PASS",
  "details": {
    "runId": "44",
    "outcome": "UNMATCHED",
    "beforeRetry": {
      "status": 409,
      "message": "实装步骤失败后必须先重试,完成后不能再次推进"
    },
    "facts": [
      {
        "stepCode": "PHYSICAL-S01",
        "status": "IN_PROGRESS",
        "targetProgressPercent": 33,
        "attemptCount": 2,
        "failureCount": 1,
        "evidenceSourceCode": "COMMAND"
      },
      {
        "stepCode": "PHYSICAL-S02",
        "status": "PENDING",
        "targetProgressPercent": 67,
        "attemptCount": 0,
        "failureCount": 0,
        "evidenceSourceCode": "NONE"
      },
      {
        "stepCode": "PHYSICAL-S03",
        "status": "PENDING",
        "targetProgressPercent": 100,
        "attemptCount": 0,
        "failureCount": 0,
        "evidenceSourceCode": "NONE"
      }
    ]
  }
}

实装逐步人工确认、事件幂等与载荷冲突 通过

查看脱敏详细记录
{
  "title": "实装逐步人工确认、事件幂等与载荷冲突",
  "status": "PASS",
  "details": {
    "runId": "44",
    "progression": [
      {
        "stepCode": "PHYSICAL-S01",
        "eventId": "MANUAL-FF103EF3-B498-4EAC-8F06-42DE46CC9CE4",
        "progress": 33,
        "replayVersion": 5,
        "alteredEventStatus": 409
      },
      {
        "stepCode": "PHYSICAL-S02",
        "eventId": "MANUAL-9D8A36B7-C161-4736-A71E-D1700E55216B",
        "progress": 67,
        "replayVersion": 6,
        "alteredEventStatus": 409
      },
      {
        "stepCode": "PHYSICAL-S03",
        "eventId": "MANUAL-1D1ADE8F-D32B-434B-A7D8-A2571E502137",
        "progress": 100,
        "replayVersion": 7,
        "alteredEventStatus": 409
      }
    ],
    "facts": [
      {
        "stepCode": "PHYSICAL-S01",
        "status": "COMPLETED",
        "targetProgressPercent": 33,
        "attemptCount": 2,
        "failureCount": 1,
        "evidenceSourceCode": "MANUAL"
      },
      {
        "stepCode": "PHYSICAL-S02",
        "status": "COMPLETED",
        "targetProgressPercent": 67,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "MANUAL"
      },
      {
        "stepCode": "PHYSICAL-S03",
        "status": "COMPLETED",
        "targetProgressPercent": 100,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "MANUAL"
      }
    ]
  }
}

PHYSICAL 提交、教员评定与结果回读 通过

查看脱敏详细记录
{
  "title": "PHYSICAL 提交、教员评定与结果回读",
  "status": "PASS",
  "details": {
    "run": {
      "id": "44",
      "assignmentId": "50",
      "status": "REVIEWED",
      "version": 9,
      "progressPercent": 100,
      "currentStepCode": "PHYSICAL-S03",
      "score": 100,
      "passed": true
    },
    "submitReplay": true,
    "reviewReplay": true,
    "facts": [
      {
        "stepCode": "PHYSICAL-S01",
        "status": "COMPLETED",
        "targetProgressPercent": 33,
        "attemptCount": 2,
        "failureCount": 1,
        "evidenceSourceCode": "MANUAL"
      },
      {
        "stepCode": "PHYSICAL-S02",
        "status": "COMPLETED",
        "targetProgressPercent": 67,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "MANUAL"
      },
      {
        "stepCode": "PHYSICAL-S03",
        "status": "COMPLETED",
        "targetProgressPercent": 100,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "MANUAL"
      }
    ]
  }
}

对抗红蓝两队各两人,按队伍共享且运行互相独立 通过

查看脱敏详细记录
{
  "title": "对抗红蓝两队各两人,按队伍共享且运行互相独立",
  "status": "PASS",
  "details": {
    "assignmentId": "51",
    "content": {
      "projectId": "164",
      "versionId": "216"
    },
    "configuration": {
      "teamSize": 2,
      "roundDurationMinutes": 7,
      "submitPositions": [
        "COMMANDER"
      ]
    },
    "runs": [
      {
        "id": "46",
        "assignmentId": "51",
        "status": "ACCEPTED",
        "version": 1,
        "progressPercent": 0,
        "currentStepCode": "",
        "score": null,
        "passed": null
      },
      {
        "id": "45",
        "assignmentId": "51",
        "status": "ACCEPTED",
        "version": 1,
        "progressPercent": 0,
        "currentStepCode": "",
        "score": null,
        "passed": null
      }
    ]
  }
}

对抗学员不能读取另一队运行明细 通过

查看脱敏详细记录
{
  "title": "对抗学员不能读取另一队运行明细",
  "status": "PASS",
  "details": {
    "requestingTeam": "RED",
    "otherRunId": "46",
    "response": {
      "status": 403,
      "message": "无权查看该训练运行"
    }
  }
}

开始命令重放不会重复激活或递增次数 通过

查看脱敏详细记录
{
  "title": "开始命令重放不会重复激活或递增次数",
  "status": "PASS",
  "details": {
    "runId": "45",
    "version": 2,
    "attemptCount": 1
  }
}

RED 队岗位越权、跳步和提前提交均拒绝 通过

查看脱敏详细记录
{
  "title": "RED 队岗位越权、跳步和提前提交均拒绝",
  "status": "PASS",
  "details": {
    "runId": "45",
    "wrongPosition": {
      "status": 403,
      "message": "当前岗位不能推进共享训练进度"
    },
    "skipped": {
      "status": 400,
      "message": "必须按发布顺序完成当前步骤,不能跳步或回退"
    },
    "earlySubmit": {
      "status": 409,
      "message": "训练步骤尚未全部完成,不能提交"
    },
    "deadlineAt": 1788623936,
    "serverNow": 1788623517
  }
}

RED 队授权动作逐步推进、重放幂等、提交负责人限制 通过

查看脱敏详细记录
{
  "title": "RED 队授权动作逐步推进、重放幂等、提交负责人限制",
  "status": "PASS",
  "details": {
    "runId": "45",
    "progression": [
      {
        "stepCode": "CONFRONTATION-S01",
        "progress": 50,
        "replayVersion": 3,
        "changedCommandStatus": 409
      },
      {
        "stepCode": "CONFRONTATION-S02",
        "progress": 100,
        "replayVersion": 4,
        "changedCommandStatus": 409
      }
    ],
    "wrongSubmitPosition": {
      "status": 403,
      "message": "共享训练仅允许任务声明的负责人岗位提交结果"
    }
  }
}

CONFRONTATION 提交、教员评定与结果回读 通过

查看脱敏详细记录
{
  "title": "CONFRONTATION 提交、教员评定与结果回读",
  "status": "PASS",
  "details": {
    "run": {
      "id": "45",
      "assignmentId": "51",
      "status": "REVIEWED",
      "version": 6,
      "progressPercent": 100,
      "currentStepCode": "CONFRONTATION-S02",
      "score": 100,
      "passed": true
    },
    "submitReplay": true,
    "reviewReplay": true,
    "facts": [
      {
        "stepCode": "CONFRONTATION-S01",
        "status": "COMPLETED",
        "targetProgressPercent": 50,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "COMMAND"
      },
      {
        "stepCode": "CONFRONTATION-S02",
        "status": "COMPLETED",
        "targetProgressPercent": 100,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "COMMAND"
      }
    ]
  }
}

红队完成不会推进蓝队进度 通过

查看脱敏详细记录
{
  "title": "红队完成不会推进蓝队进度",
  "status": "PASS",
  "details": {
    "redRunId": "45",
    "blueRun": {
      "id": "46",
      "assignmentId": "51",
      "status": "ACCEPTED",
      "version": 1,
      "progressPercent": 0,
      "currentStepCode": "",
      "score": null,
      "passed": null
    }
  }
}

开始命令重放不会重复激活或递增次数 通过

查看脱敏详细记录
{
  "title": "开始命令重放不会重复激活或递增次数",
  "status": "PASS",
  "details": {
    "runId": "46",
    "version": 2,
    "attemptCount": 1
  }
}

BLUE 队岗位越权、跳步和提前提交均拒绝 通过

查看脱敏详细记录
{
  "title": "BLUE 队岗位越权、跳步和提前提交均拒绝",
  "status": "PASS",
  "details": {
    "runId": "46",
    "wrongPosition": {
      "status": 403,
      "message": "当前岗位不能推进共享训练进度"
    },
    "skipped": {
      "status": 400,
      "message": "必须按发布顺序完成当前步骤,不能跳步或回退"
    },
    "earlySubmit": {
      "status": 409,
      "message": "训练步骤尚未全部完成,不能提交"
    },
    "deadlineAt": 1788623942,
    "serverNow": 1788623523
  }
}

BLUE 队授权动作逐步推进、重放幂等、提交负责人限制 通过

查看脱敏详细记录
{
  "title": "BLUE 队授权动作逐步推进、重放幂等、提交负责人限制",
  "status": "PASS",
  "details": {
    "runId": "46",
    "progression": [
      {
        "stepCode": "CONFRONTATION-S01",
        "progress": 50,
        "replayVersion": 3,
        "changedCommandStatus": 409
      },
      {
        "stepCode": "CONFRONTATION-S02",
        "progress": 100,
        "replayVersion": 4,
        "changedCommandStatus": 409
      }
    ],
    "wrongSubmitPosition": {
      "status": 403,
      "message": "共享训练仅允许任务声明的负责人岗位提交结果"
    }
  }
}

CONFRONTATION 提交、教员评定与结果回读 通过

查看脱敏详细记录
{
  "title": "CONFRONTATION 提交、教员评定与结果回读",
  "status": "PASS",
  "details": {
    "run": {
      "id": "46",
      "assignmentId": "51",
      "status": "REVIEWED",
      "version": 6,
      "progressPercent": 100,
      "currentStepCode": "CONFRONTATION-S02",
      "score": 100,
      "passed": true
    },
    "submitReplay": true,
    "reviewReplay": true,
    "facts": [
      {
        "stepCode": "CONFRONTATION-S01",
        "status": "COMPLETED",
        "targetProgressPercent": 50,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "COMMAND"
      },
      {
        "stepCode": "CONFRONTATION-S02",
        "status": "COMPLETED",
        "targetProgressPercent": 100,
        "attemptCount": 1,
        "failureCount": 0,
        "evidenceSourceCode": "COMMAND"
      }
    ]
  }
}

正式任务快照固定训练、场景与模型发布版本 通过

查看脱敏详细记录
{
  "title": "正式任务快照固定训练、场景与模型发布版本",
  "status": "PASS",
  "details": {
    "snapshots": [
      {
        "assignmentId": "50",
        "channel": "PHYSICAL",
        "content": {
          "projectId": "163",
          "versionId": "215"
        },
        "frozenScene": {
          "projectId": "159",
          "versionId": "209",
          "models": [
            {
              "projectId": "156",
              "versionId": "204",
              "assetCode": "MODEL_MTO6WI6K_08-CESIUMMILKTRUCK"
            }
          ]
        }
      },
      {
        "assignmentId": "51",
        "channel": "CONFRONTATION",
        "content": {
          "projectId": "164",
          "versionId": "216"
        },
        "frozenScene": {
          "projectId": "160",
          "versionId": "210",
          "models": [
            {
              "projectId": "157",
              "versionId": "201",
              "assetCode": "MODEL_MTO6V5W6_09-FOX"
            }
          ]
        }
      }
    ]
  }
}
api-evidence.json · 完整记录
{
  "title": "实装人工事件与红蓝对抗正式 API 闭环",
  "status": "PASS",
  "startedAt": "2026-09-05T15:48:46.342Z",
  "baseURL": "http://127.0.0.1:6180",
  "method": "真实 Auth / Gateway / Tran API;新建隔离学生与开发测试任务;不连接设备、视觉推理或外部通知。",
  "references": {
    "PHYSICAL": {
      "projectId": "163",
      "versionId": "215"
    },
    "CONFRONTATION": {
      "projectId": "164",
      "versionId": "216"
    }
  },
  "checks": [
    {
      "title": "开始命令重放不会重复激活或递增次数",
      "status": "PASS",
      "details": {
        "runId": "44",
        "version": 2,
        "attemptCount": 1
      }
    },
    {
      "title": "实装任务固定发布版本、分配学员并开始",
      "status": "PASS",
      "details": {
        "assignmentId": "50",
        "run": {
          "id": "44",
          "assignmentId": "50",
          "status": "IN_PROGRESS",
          "version": 2,
          "progressPercent": 0,
          "currentStepCode": "PHYSICAL-S01",
          "score": null,
          "passed": null
        },
        "content": {
          "projectId": "163",
          "versionId": "215"
        },
        "rules": [
          {
            "stepCode": "PHYSICAL-S01",
            "source": "MANUAL",
            "eventType": "step.physical-s01.confirmed",
            "progressPercent": 33
          },
          {
            "stepCode": "PHYSICAL-S02",
            "source": "MANUAL",
            "eventType": "step.physical-s02.confirmed",
            "progressPercent": 67
          },
          {
            "stepCode": "PHYSICAL-S03",
            "source": "MANUAL",
            "eventType": "step.physical-s03.confirmed",
            "progressPercent": 100
          }
        ]
      }
    },
    {
      "title": "实装拒绝普通进度接口、抢跑、提前提交及错误事件身份",
      "status": "PASS",
      "details": {
        "runId": "44",
        "forbiddenProgress": {
          "status": 403,
          "message": "实装运行只能由设备、视觉或人工确认事件推进"
        },
        "prematureSubmit": {
          "status": 409,
          "message": "训练步骤尚未全部完成,不能提交"
        },
        "skipped": {
          "status": 409,
          "message": "物理事件必须匹配当前待完成步骤,不能跳步或回退"
        },
        "untrustedDevice": {
          "status": 403,
          "message": "无权执行此操作"
        },
        "managerManual": {
          "status": 403,
          "message": "当前学员不是该运行成员"
        },
        "progressUnchanged": 0
      }
    },
    {
      "title": "实装不匹配事件失败,必须重试后才可继续",
      "status": "PASS",
      "details": {
        "runId": "44",
        "outcome": "UNMATCHED",
        "beforeRetry": {
          "status": 409,
          "message": "实装步骤失败后必须先重试,完成后不能再次推进"
        },
        "facts": [
          {
            "stepCode": "PHYSICAL-S01",
            "status": "IN_PROGRESS",
            "targetProgressPercent": 33,
            "attemptCount": 2,
            "failureCount": 1,
            "evidenceSourceCode": "COMMAND"
          },
          {
            "stepCode": "PHYSICAL-S02",
            "status": "PENDING",
            "targetProgressPercent": 67,
            "attemptCount": 0,
            "failureCount": 0,
            "evidenceSourceCode": "NONE"
          },
          {
            "stepCode": "PHYSICAL-S03",
            "status": "PENDING",
            "targetProgressPercent": 100,
            "attemptCount": 0,
            "failureCount": 0,
            "evidenceSourceCode": "NONE"
          }
        ]
      }
    },
    {
      "title": "实装逐步人工确认、事件幂等与载荷冲突",
      "status": "PASS",
      "details": {
        "runId": "44",
        "progression": [
          {
            "stepCode": "PHYSICAL-S01",
            "eventId": "MANUAL-FF103EF3-B498-4EAC-8F06-42DE46CC9CE4",
            "progress": 33,
            "replayVersion": 5,
            "alteredEventStatus": 409
          },
          {
            "stepCode": "PHYSICAL-S02",
            "eventId": "MANUAL-9D8A36B7-C161-4736-A71E-D1700E55216B",
            "progress": 67,
            "replayVersion": 6,
            "alteredEventStatus": 409
          },
          {
            "stepCode": "PHYSICAL-S03",
            "eventId": "MANUAL-1D1ADE8F-D32B-434B-A7D8-A2571E502137",
            "progress": 100,
            "replayVersion": 7,
            "alteredEventStatus": 409
          }
        ],
        "facts": [
          {
            "stepCode": "PHYSICAL-S01",
            "status": "COMPLETED",
            "targetProgressPercent": 33,
            "attemptCount": 2,
            "failureCount": 1,
            "evidenceSourceCode": "MANUAL"
          },
          {
            "stepCode": "PHYSICAL-S02",
            "status": "COMPLETED",
            "targetProgressPercent": 67,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "MANUAL"
          },
          {
            "stepCode": "PHYSICAL-S03",
            "status": "COMPLETED",
            "targetProgressPercent": 100,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "MANUAL"
          }
        ]
      }
    },
    {
      "title": "PHYSICAL 提交、教员评定与结果回读",
      "status": "PASS",
      "details": {
        "run": {
          "id": "44",
          "assignmentId": "50",
          "status": "REVIEWED",
          "version": 9,
          "progressPercent": 100,
          "currentStepCode": "PHYSICAL-S03",
          "score": 100,
          "passed": true
        },
        "submitReplay": true,
        "reviewReplay": true,
        "facts": [
          {
            "stepCode": "PHYSICAL-S01",
            "status": "COMPLETED",
            "targetProgressPercent": 33,
            "attemptCount": 2,
            "failureCount": 1,
            "evidenceSourceCode": "MANUAL"
          },
          {
            "stepCode": "PHYSICAL-S02",
            "status": "COMPLETED",
            "targetProgressPercent": 67,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "MANUAL"
          },
          {
            "stepCode": "PHYSICAL-S03",
            "status": "COMPLETED",
            "targetProgressPercent": 100,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "MANUAL"
          }
        ]
      }
    },
    {
      "title": "对抗红蓝两队各两人,按队伍共享且运行互相独立",
      "status": "PASS",
      "details": {
        "assignmentId": "51",
        "content": {
          "projectId": "164",
          "versionId": "216"
        },
        "configuration": {
          "teamSize": 2,
          "roundDurationMinutes": 7,
          "submitPositions": [
            "COMMANDER"
          ]
        },
        "runs": [
          {
            "id": "46",
            "assignmentId": "51",
            "status": "ACCEPTED",
            "version": 1,
            "progressPercent": 0,
            "currentStepCode": "",
            "score": null,
            "passed": null
          },
          {
            "id": "45",
            "assignmentId": "51",
            "status": "ACCEPTED",
            "version": 1,
            "progressPercent": 0,
            "currentStepCode": "",
            "score": null,
            "passed": null
          }
        ]
      }
    },
    {
      "title": "对抗学员不能读取另一队运行明细",
      "status": "PASS",
      "details": {
        "requestingTeam": "RED",
        "otherRunId": "46",
        "response": {
          "status": 403,
          "message": "无权查看该训练运行"
        }
      }
    },
    {
      "title": "开始命令重放不会重复激活或递增次数",
      "status": "PASS",
      "details": {
        "runId": "45",
        "version": 2,
        "attemptCount": 1
      }
    },
    {
      "title": "RED 队岗位越权、跳步和提前提交均拒绝",
      "status": "PASS",
      "details": {
        "runId": "45",
        "wrongPosition": {
          "status": 403,
          "message": "当前岗位不能推进共享训练进度"
        },
        "skipped": {
          "status": 400,
          "message": "必须按发布顺序完成当前步骤,不能跳步或回退"
        },
        "earlySubmit": {
          "status": 409,
          "message": "训练步骤尚未全部完成,不能提交"
        },
        "deadlineAt": 1788623936,
        "serverNow": 1788623517
      }
    },
    {
      "title": "RED 队授权动作逐步推进、重放幂等、提交负责人限制",
      "status": "PASS",
      "details": {
        "runId": "45",
        "progression": [
          {
            "stepCode": "CONFRONTATION-S01",
            "progress": 50,
            "replayVersion": 3,
            "changedCommandStatus": 409
          },
          {
            "stepCode": "CONFRONTATION-S02",
            "progress": 100,
            "replayVersion": 4,
            "changedCommandStatus": 409
          }
        ],
        "wrongSubmitPosition": {
          "status": 403,
          "message": "共享训练仅允许任务声明的负责人岗位提交结果"
        }
      }
    },
    {
      "title": "CONFRONTATION 提交、教员评定与结果回读",
      "status": "PASS",
      "details": {
        "run": {
          "id": "45",
          "assignmentId": "51",
          "status": "REVIEWED",
          "version": 6,
          "progressPercent": 100,
          "currentStepCode": "CONFRONTATION-S02",
          "score": 100,
          "passed": true
        },
        "submitReplay": true,
        "reviewReplay": true,
        "facts": [
          {
            "stepCode": "CONFRONTATION-S01",
            "status": "COMPLETED",
            "targetProgressPercent": 50,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "COMMAND"
          },
          {
            "stepCode": "CONFRONTATION-S02",
            "status": "COMPLETED",
            "targetProgressPercent": 100,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "COMMAND"
          }
        ]
      }
    },
    {
      "title": "红队完成不会推进蓝队进度",
      "status": "PASS",
      "details": {
        "redRunId": "45",
        "blueRun": {
          "id": "46",
          "assignmentId": "51",
          "status": "ACCEPTED",
          "version": 1,
          "progressPercent": 0,
          "currentStepCode": "",
          "score": null,
          "passed": null
        }
      }
    },
    {
      "title": "开始命令重放不会重复激活或递增次数",
      "status": "PASS",
      "details": {
        "runId": "46",
        "version": 2,
        "attemptCount": 1
      }
    },
    {
      "title": "BLUE 队岗位越权、跳步和提前提交均拒绝",
      "status": "PASS",
      "details": {
        "runId": "46",
        "wrongPosition": {
          "status": 403,
          "message": "当前岗位不能推进共享训练进度"
        },
        "skipped": {
          "status": 400,
          "message": "必须按发布顺序完成当前步骤,不能跳步或回退"
        },
        "earlySubmit": {
          "status": 409,
          "message": "训练步骤尚未全部完成,不能提交"
        },
        "deadlineAt": 1788623942,
        "serverNow": 1788623523
      }
    },
    {
      "title": "BLUE 队授权动作逐步推进、重放幂等、提交负责人限制",
      "status": "PASS",
      "details": {
        "runId": "46",
        "progression": [
          {
            "stepCode": "CONFRONTATION-S01",
            "progress": 50,
            "replayVersion": 3,
            "changedCommandStatus": 409
          },
          {
            "stepCode": "CONFRONTATION-S02",
            "progress": 100,
            "replayVersion": 4,
            "changedCommandStatus": 409
          }
        ],
        "wrongSubmitPosition": {
          "status": 403,
          "message": "共享训练仅允许任务声明的负责人岗位提交结果"
        }
      }
    },
    {
      "title": "CONFRONTATION 提交、教员评定与结果回读",
      "status": "PASS",
      "details": {
        "run": {
          "id": "46",
          "assignmentId": "51",
          "status": "REVIEWED",
          "version": 6,
          "progressPercent": 100,
          "currentStepCode": "CONFRONTATION-S02",
          "score": 100,
          "passed": true
        },
        "submitReplay": true,
        "reviewReplay": true,
        "facts": [
          {
            "stepCode": "CONFRONTATION-S01",
            "status": "COMPLETED",
            "targetProgressPercent": 50,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "COMMAND"
          },
          {
            "stepCode": "CONFRONTATION-S02",
            "status": "COMPLETED",
            "targetProgressPercent": 100,
            "attemptCount": 1,
            "failureCount": 0,
            "evidenceSourceCode": "COMMAND"
          }
        ]
      }
    },
    {
      "title": "正式任务快照固定训练、场景与模型发布版本",
      "status": "PASS",
      "details": {
        "snapshots": [
          {
            "assignmentId": "50",
            "channel": "PHYSICAL",
            "content": {
              "projectId": "163",
              "versionId": "215"
            },
            "frozenScene": {
              "projectId": "159",
              "versionId": "209",
              "models": [
                {
                  "projectId": "156",
                  "versionId": "204",
                  "assetCode": "MODEL_MTO6WI6K_08-CESIUMMILKTRUCK"
                }
              ]
            }
          },
          {
            "assignmentId": "51",
            "channel": "CONFRONTATION",
            "content": {
              "projectId": "164",
              "versionId": "216"
            },
            "frozenScene": {
              "projectId": "160",
              "versionId": "210",
              "models": [
                {
                  "projectId": "157",
                  "versionId": "201",
                  "assetCode": "MODEL_MTO6V5W6_09-FOX"
                }
              ]
            }
          }
        ]
      }
    }
  ],
  "assignments": [
    {
      "id": "50",
      "code": "UTE2E-MODES-MTOK5BBA-PHYSICAL",
      "channel": "PHYSICAL",
      "contentProjectId": "163",
      "contentVersionId": "215",
      "status": "PUBLISHED",
      "version": 1,
      "frozenScene": {
        "projectId": "159",
        "versionId": "209",
        "models": [
          {
            "projectId": "156",
            "versionId": "204",
            "assetCode": "MODEL_MTO6WI6K_08-CESIUMMILKTRUCK"
          }
        ]
      }
    },
    {
      "id": "51",
      "code": "UTE2E-MODES-MTOK5BBA-CONFRONTATION",
      "channel": "CONFRONTATION",
      "contentProjectId": "164",
      "contentVersionId": "216",
      "status": "PUBLISHED",
      "version": 1,
      "frozenScene": {
        "projectId": "160",
        "versionId": "210",
        "models": [
          {
            "projectId": "157",
            "versionId": "201",
            "assetCode": "MODEL_MTO6V5W6_09-FOX"
          }
        ]
      }
    }
  ],
  "runs": [
    {
      "id": "44",
      "assignmentId": "50",
      "status": "REVIEWED",
      "version": 9,
      "progressPercent": 100,
      "currentStepCode": "PHYSICAL-S03",
      "score": 100,
      "passed": true,
      "channel": "PHYSICAL",
      "team": "NEUTRAL",
      "stepFacts": [
        {
          "stepCode": "PHYSICAL-S01",
          "status": "COMPLETED",
          "targetProgressPercent": 33,
          "attemptCount": 2,
          "failureCount": 1,
          "evidenceSourceCode": "MANUAL"
        },
        {
          "stepCode": "PHYSICAL-S02",
          "status": "COMPLETED",
          "targetProgressPercent": 67,
          "attemptCount": 1,
          "failureCount": 0,
          "evidenceSourceCode": "MANUAL"
        },
        {
          "stepCode": "PHYSICAL-S03",
          "status": "COMPLETED",
          "targetProgressPercent": 100,
          "attemptCount": 1,
          "failureCount": 0,
          "evidenceSourceCode": "MANUAL"
        }
      ]
    },
    {
      "id": "45",
      "assignmentId": "51",
      "status": "REVIEWED",
      "version": 6,
      "progressPercent": 100,
      "currentStepCode": "CONFRONTATION-S02",
      "score": 100,
      "passed": true,
      "channel": "CONFRONTATION",
      "team": "RED",
      "stepFacts": [
        {
          "stepCode": "CONFRONTATION-S01",
          "status": "COMPLETED",
          "targetProgressPercent": 50,
          "attemptCount": 1,
          "failureCount": 0,
          "evidenceSourceCode": "COMMAND"
        },
        {
          "stepCode": "CONFRONTATION-S02",
          "status": "COMPLETED",
          "targetProgressPercent": 100,
          "attemptCount": 1,
          "failureCount": 0,
          "evidenceSourceCode": "COMMAND"
        }
      ]
    },
    {
      "id": "46",
      "assignmentId": "51",
      "status": "REVIEWED",
      "version": 6,
      "progressPercent": 100,
      "currentStepCode": "CONFRONTATION-S02",
      "score": 100,
      "passed": true,
      "channel": "CONFRONTATION",
      "team": "BLUE",
      "stepFacts": [
        {
          "stepCode": "CONFRONTATION-S01",
          "status": "COMPLETED",
          "targetProgressPercent": 50,
          "attemptCount": 1,
          "failureCount": 0,
          "evidenceSourceCode": "COMMAND"
        },
        {
          "stepCode": "CONFRONTATION-S02",
          "status": "COMPLETED",
          "targetProgressPercent": 100,
          "attemptCount": 1,
          "failureCount": 0,
          "evidenceSourceCode": "COMMAND"
        }
      ]
    }
  ],
  "actors": [
    {
      "userId": "95",
      "team": "RED",
      "position": "COMMANDER",
      "departmentId": "5"
    },
    {
      "userId": "96",
      "team": "RED",
      "position": "OPERATOR",
      "departmentId": "5"
    },
    {
      "userId": "97",
      "team": "BLUE",
      "position": "COMMANDER",
      "departmentId": "5"
    },
    {
      "userId": "98",
      "team": "BLUE",
      "position": "OPERATOR",
      "departmentId": "5"
    }
  ],
  "requests": [
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments/50/publish",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments/50/accept",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/start",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/start",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44/steps",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/44/progress",
      "status": 403
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/submit",
      "status": 409
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 409
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 403
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 403
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44/steps",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 409
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/start",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44/steps",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 409
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 409
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/physical-events",
      "status": 409
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44/steps",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/submit",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/submit",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/review",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/44/review",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/44/steps",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments/51/publish",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments/51/accept",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments/51/accept",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments/51/accept",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/assignments/51/accept",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs?assignmentId=51&size=100",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/46",
      "status": 403
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/start",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/start",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/45/steps",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/45/execution",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 403
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 400
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/submit",
      "status": 409
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/45",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 409
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/45/progress",
      "status": 409
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/submit",
      "status": 403
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/submit",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/submit",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/review",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/45/review",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/45/steps",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/46",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/start",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/start",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/46/steps",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/46/execution",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 403
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 400
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/submit",
      "status": 409
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/46",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 409
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 200
    },
    {
      "method": "PUT",
      "path": "/api/tran/v1/teaching/runs/46/progress",
      "status": 409
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/submit",
      "status": 403
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/submit",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/submit",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/review",
      "status": 200
    },
    {
      "method": "POST",
      "path": "/api/tran/v1/teaching/runs/46/review",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/runs/46/steps",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/assignments/50",
      "status": 200
    },
    {
      "method": "GET",
      "path": "/api/tran/v1/teaching/assignments/51",
      "status": 200
    }
  ],
  "limitations": [
    "实装事件均为本次自动化提交的 MANUAL 人工确认或明确的权限拒绝测试,不代表真实设备、PLC、摄像机或视觉模型联调。",
    "教学运行结果来自正式 API;默认实装离线回放和默认对抗本地工作台的显示另行记录,不混同为服务端运行闭环。",
    "对抗按四名隔离学员的独立会话依次操作,检查服务端截止时间已生效;未等待整局自然超时,也不代表多人同时操作的压力或网络同步测试。",
    "测试账号使用本次随机密码,密码与会话仅在运行内存中;报告只保留用户 ID、队伍和岗位以便追溯。"
  ],
  "finishedAt": "2026-09-05T15:58:56.293Z",
  "retainedData": {
    "assignments": [
      "50",
      "51"
    ],
    "runs": [
      "44",
      "45",
      "46"
    ],
    "users": [
      "95",
      "96",
      "97",
      "98"
    ],
    "note": "仅新建本次开发测试数据,未修改或删除既有账号、任务与运行。"
  }
}

测试命令与构建

pnpm run build 通过

vue-tsc、Vite构建和legacy iframe分发校验均通过;仅已有包体积提示。

node --test tools/training-*.test.mjs(本次8个聚焦文件) 通过

94/94通过,涵盖封面、场景、真实模型、目标、元数据、模式与步骤兼容。

pnpm run test:training-legacy 通过

两项既有训练/地形合同检查通过。

content-training-studio.spec.ts / Edge 通过

7/7通过(mock API的工作台回归),无跳过、无不稳定用例,独立报告studio-regression/html/index.html。

UTE2E_TRAINING_MODES=1 UTE2E_BASE_URL=http://192.168.31.168:6180 node tools/training-scene-visibility.e2e.mjs 通过

独立Edge会话2/2通过,真实LAN服务、禁止业务写请求;模型可见像素差、固定场景依赖、JPEG尺寸与SHA-256全部通过。

node tools/training-modes-api-live.mjs(163:215;164:216) 通过

18/18检查组通过,90次正式教学API请求;含训练/场景/模型固定快照只读复核,详见api-evidence.json。

真实浏览器截图

截图只来自实际存在的文件;API 请求结果单列,不以 UI 截图代替。

范围、限制与待确认项

实测边界与限制

需要另行确认的功能范围