您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

2624 行
254 KiB

  1. <!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>装备模型编辑器 · 全功能闭环验收</title><style>
  2. :root{--bg:#f3f5f7;--paper:#fff;--ink:#182f3e;--muted:#617481;--line:#dce4e8;--green:#0c796a;--navy:#102d40;--amber:#9b650d;--red:#ae343d}*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:75px}body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.7 "Microsoft YaHei","Segoe UI",sans-serif}a{color:#08798a;text-decoration:none}a:hover{text-decoration:underline}header{background:linear-gradient(120deg,#102d40,#135744);color:#fff;padding:50px max(24px,calc((100vw - 1480px)/2)) 40px}header p{color:#d2e4e8;max-width:960px;margin:10px 0 0}.eyebrow{text-transform:uppercase;font-size:12px;letter-spacing:2px;color:#9cdacb}h1{font-size:36px;line-height:1.4;letter-spacing:1px;margin:12px 0}h2{font-size:27px;margin:3px 0 18px}h3{font-size:19px;margin:0 0 14px}h4{margin:0 0 9px;font-size:16px}p{margin:8px 0 15px}nav{position:sticky;top:0;background:#fffefc;z-index:5;border-bottom:1px solid var(--line);padding:13px 22px;display:flex;justify-content:center;gap:28px;flex-wrap:wrap}nav a{font-weight:600;color:#375565}main{max-width:1480px;margin:auto;padding:28px 24px 65px}section{margin:38px 0}.section-label{font-size:12px;letter-spacing:2px;color:#698392;font-weight:bold}.panel,.notice{padding:25px;background:var(--paper);border:1px solid var(--line);border-radius:13px;margin-bottom:18px}.notice{border-left:5px solid #7096b0}.notice.fail{background:#fff4f4;border-left-color:var(--red)}.notice.pass{background:#eef9f4;border-left-color:var(--green)}.notice.pending,.notice.warn{background:#fffbef;border-left-color:#ca941f}.notice strong{font-size:19px}.muted,small{color:var(--muted)}.badge{display:inline-block;white-space:nowrap;padding:2px 9px;border-radius:20px;font-size:12px;font-weight:600;line-height:1.7;background:#edf1f4;color:#576f80}.badge.pass{background:#dcf2e6;color:#086343}.badge.fail{background:#ffe0e0;color:#a52c37}.badge.pending,.badge.warn{background:#fff0c8;color:#825508}.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:15px;margin-top:23px}.stats>div{border:1px solid var(--line);background:#fff;padding:19px 23px;border-radius:12px}.stats span,.stats small{display:block}.stats b{font-size:31px;color:var(--navy);font-variant-numeric:tabular-nums}.stats i{font-style:normal;font-size:17px;font-weight:400;color:#708795}.flow{display:grid;grid-template-columns:repeat(5,1fr);gap:14px}.flow article{background:#fff;border:1px solid var(--line);padding:18px;border-radius:10px}.flow b{display:block;color:#17655d}.flow p{font-size:13px;margin-bottom:0}.grid2{display:grid;grid-template-columns:1fr 1fr;gap:18px}.table-scroll{overflow:auto;border:1px solid var(--line);border-radius:9px}table{border-collapse:collapse;width:100%;font-size:13px;text-align:left}th{background:#eaf0f3;color:#314f60;padding:12px;white-space:nowrap}td{padding:13px 12px;border-top:1px solid var(--line);vertical-align:top;min-width:130px}tr:nth-child(even)td{background:#fafcfd}.matrix td:first-child{min-width:220px}.matrix td:nth-child(3){min-width:240px}.matrix td:nth-child(4){min-width:220px}.matrix td:nth-child(5){min-width:250px}.matrix strong,.matrix code{display:block}.matrix code{font-size:11px;color:#738a96;margin-top:4px}.matrix small{display:block}.matrix details summary{cursor:pointer;color:#097688}.matrix-group{margin-top:25px}.filters{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:18px 0}.filters input,.filters select{font:inherit;border:1px solid #c8d6df;padding:9px 13px;border-radius:7px;background:white}.filters input{min-width:260px;flex:1}.legend{font-size:13px;color:var(--muted)}.decision{border-top:4px solid #c5912e}.decision .decision-id{font-size:12px;color:#8a6018;font-weight:bold}.decision p{font-size:14px}.decision dt{font-weight:bold;color:#25495a;margin-top:14px}.decision dd{margin:3px 0 0;color:#536c7a;font-size:14px}.gallery{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}figure{margin:0;background:#fff;border:1px solid var(--line);border-radius:11px;overflow:hidden}figure img{display:block;aspect-ratio:16/9;width:100%;object-fit:contain;background:#dbe3e9}figcaption{padding:17px}figcaption strong{display:inline}figcaption .badge{margin-left:9px}figcaption p{font-size:13px;margin:9px 0}figcaption small{font-size:11px;overflow-wrap:anywhere}.shot-number{font-size:12px;color:#71929c;margin-right:9px}pre{overflow:auto;max-height:420px;white-space:pre-wrap;overflow-wrap:anywhere;background:#102c3f;color:#dfedf4;padding:20px;border-radius:9px;font:12px/1.65 Consolas,monospace}details summary{cursor:pointer;font-weight:600}details[open] summary{margin-bottom:12px}.links{display:flex;flex-wrap:wrap;gap:8px 22px}.links a{font-size:13px;overflow-wrap:anywhere}footer{border-top:1px solid var(--line);padding-top:20px;font-size:12px;color:var(--muted)}dialog{border:0;border-radius:12px;padding:0;width:min(96vw,1900px);max-width:none;background:#102638;color:white}dialog::backdrop{background:#03111bd9}dialog img{display:block;width:100%;max-height:85vh;object-fit:contain}.dialog-bar{padding:13px 20px;display:flex;gap:20px;align-items:center;justify-content:space-between}.dialog-bar button{padding:7px 15px;border:1px solid #67828d;color:white;background:transparent;border-radius:6px;cursor:pointer}.dialog-bar a{color:#a0deec}.hidden{display:none!important}@media(max-width:1000px){.gallery,.flow{grid-template-columns:repeat(2,1fr)}.stats{grid-template-columns:repeat(2,1fr)}.grid2{grid-template-columns:1fr}h1{font-size:28px}}@media(max-width:600px){main{padding:20px 12px}.panel{padding:17px}.gallery,.flow{grid-template-columns:1fr}nav{gap:8px 15px;font-size:12px}}@media print{nav,.filters{display:none}.gallery{grid-template-columns:1fr 1fr}section{break-before:auto}.table-scroll{overflow:visible}header{padding:25px}.panel{break-inside:avoid}body{background:#fff}}
  3. </style></head><body><header><div class="eyebrow">MODEL AUTHORING · CLOSURE REVIEW · 2026.09.06</div><h1>装备模型编辑器<br>全功能闭环审查与验收</h1><p>沿资料 → 产品原型 → 设计 → 开发 → 测试核查每一个可达动作。用狐狸、牛奶卡车等轻量模型验证通用编排能力,保留现有业务流程与版本数据。</p></header>
  4. <nav><a href="#overview">验收概况</a><a href="#materials">01 资料</a><a href="#prototype">02 原型</a><a href="#design">03 设计</a><a href="#development">04 开发</a><a href="#testing">05 测试</a><a href="#decisions">待确认范围</a><a href="#screenshots">截图证据</a></nav><main>
  5. <section id="overview"><div class="notice pass"><strong>已列功能的记录验证通过</strong><p><span class="badge pass">已验证</span> · 报告生成:2026/9/6 16:34:35(北京时间)。源码已接通、合同测试和真实浏览器验证分别记录;没有断言关联的功能仍为待验证。</p></div><div class="stats"><div><span>功能清单</span><b>103</b><small>全部可达动作逐项整理</small></div><div><span>逐项证据</span><b>103<i> / 103</i></b><small>0 项仍待验证</small></div><div><span>浏览器 E2E</span><b>19<i> / 19</i></b><small>0 失败 · 最终轮已标记</small></div><div><span>截图 / 待确认</span><b>41<i> / 3</i></b><small>截图按实际文件读取</small></div></div><p class="legend">“已实现/本轮修复”是源码状态;绿色“已验证”要求独立证据。过程截图与测试总数不能自动把 103 个功能全部变成通过。</p></section>
  6. <section id="materials"><div class="section-label">01 / 资料</div><h2>从参考资料提取通用能力</h2><div class="panel"><p>原始两份 PDF 共 11 页已由主代理完整渲染并视觉阅读。原始诉求集中在部件选择、操作步骤、交互反馈和结果追踪。本轮以狐狸、牛奶卡车等轻量模型验证部件选择、流程编排、交互反馈和结果保存。</p><p><a href="../../../../%E6%96%87%E6%A1%A3/%E7%BB%B4%E4%BF%AE%E8%AE%AD%E7%BB%83%E5%86%85%E5%AE%B9%E8%AE%BE%E8%AE%A1.pdf">维修训练内容设计.pdf</a> · <a href="../../../../%E6%96%87%E6%A1%A3/%E7%94%B5%E5%99%A8%E6%8E%A7%E5%88%B6%E7%B3%BB%E7%BB%9F%E6%95%85%E9%9A%9C%E7%BB%B4%E4%BF%AE%E8%84%9A%E6%9C%AC.pdf">电器控制系统故障维修脚本.pdf</a>。报告仅链接原文,不复制全文或整页图片。</p><div class="table-scroll"><table><thead><tr><th>资料能力</th><th>本轮可观察结果</th><th>矩阵追踪</th></tr></thead><tbody><tr><td>部件级选择与操作</td><td>整体与部件区分;树、视口和属性联动;操作后可保存重开。</td><td>selection.scope / selection.sync / property.*</td></tr><tr><td>动作流程</td><td>时间轴关键帧、曲线插值、蓝图顺序和真假分支有实际执行结果。</td><td>timeline.* / curve.* / blueprint.*</td></tr><tr><td>交互反馈</td><td>点击/双击/自动事件、高亮、文字提示、停止和错误反馈与对象匹配。</td><td>blueprint.click / double-click / auto / highlight / message</td></tr><tr><td>结果追踪</td><td>模型版本、封面、引用和本次运行结果有证据;明确运行日志不是教学成绩或审计。</td><td>publish.* / feedback.* / project.conflict</td></tr></tbody></table></div></div></section>
  7. <section id="prototype"><div class="section-label">02 / 产品原型</div><h2>确认用户实际使用的执行入口</h2><div class="flow"><article><b>内容模型列表</b><p>选中正式项目,进入模型编辑路由。</p></article><article><b>Vue 宿主</b><p>传 projectId / api=1,注入权限与未保存确认。</p></article><article><b>同源 iframe</b><p>承载 legacy-model-editor/editor.html。</p></article><article><b>真实原型源码</b><p>main.js + timeline.js + blueprint.js,经 stage 构建。</p></article><article><b>内容 API</b><p>受控资产、项目版本、保存和发布。</p></article></div><div class="panel"><p>当前默认入口由 <a href="../../../unreal_tran_web/src/config/content.ts">content.ts</a> 和 <a href="../../../unreal_tran_web/src/views/content/LegacyModelEditorView.vue">LegacyModelEditorView.vue</a> 确定,<a href="../../../unreal_tran_web/scripts/stage-legacy-model-editor.mjs">stage-legacy-model-editor.mjs</a> 将真实原型源码打入静态资源。备用 DigitalTwinEditor.js 不是本轮默认入口。</p><p>覆盖顶部工具、场景树/资源库、三维视口、对象属性/组件说明、时间轴、曲线、蓝图、发布面板、运行日志和快捷键。代码中保留但没有可达按钮的“训练场景 JSON 导入”不计为用户可达功能。</p></div></section>
  8. <section id="design"><div class="section-label">03 / 设计</div><h2>明确保存、运行与验证的边界</h2><div class="grid2"><article class="panel"><h3>工程数据闭环</h3><p>对象变换/材质/自定义字段、时间轴/蓝图和环境稳定引用必须能保存、重开、撤销及 JSON 往返。临时 blob 只用于渲染,服务端资产标识用于持久化。</p><p>导入、截图、保存与发布期间保留互斥和乐观锁;失败不得用成功消息掩盖,也不得发布半绑定资源。</p></article><article class="panel"><h3>界面与业务范围</h3><p>网格、线框、PBR、透视和展开布局属于当前视图选项,未跨刷新保存不作为缺陷。运行日志属于本次运行记录,不等同审计和教学成绩。</p><p>现有组件新增是名称标记;现有离线 HTML 是步骤演示;下游自动执行模型动作须另行确认。</p></article></div></section>
  9. <section id="development"><div class="section-label">04 / 开发</div><h2>全功能覆盖矩阵</h2><p>每行列出实际执行入口、实现状态、边界、对应修复及独立验证要求。<a href="feature-catalog.json">静态功能清单</a> · <a href="coverage.json">带证据的矩阵 JSON</a> · <a href="data/inventory-main.md">修复前基线与实施记录</a>。</p><div class="filters"><input id="feature-search" type="search" placeholder="搜索功能、ID、边界或修复"><select id="feature-state" aria-label="验证状态筛选"><option value="all">全部验证状态</option><option value="PENDING">待验证</option><option value="PASS">已验证</option><option value="FAIL">失败</option><option value="WARN">需复核</option></select><span id="feature-visible">103 项</span></div>
  10. <div class="grid2"><article class="panel"><h3>只读模型的搜索、原生动画选择与键盘预览</h3><p>权限桥误把查看控件的键盘交互当成内容编辑,导致只读用户不能在搜索框输入、切换原生动画或按 Enter 进入预览。</p><p>按实际查看控件放行键盘输入/选择/激活;模型编辑、内容上传/保存/发布仍依对应权限阻断。</p><p class="muted">真实 DOM 权限桥 14/14 通过;最终完整19条E2E全部通过,其中管理员用例验证真实键盘搜索、原生动画切换与Enter播放/暂停,期间没有内容写请求,直接创建接口返回403。</p><small><a href="../../../unreal_tran_web/src/features/editors/model/legacy-iframe-permissions.ts">源码</a> · <a href="../../tools/content-permissions.test.mjs">聚焦测试</a></small></article><article class="panel"><h3>Auth / Tran 连接有效性检查增加时限与空闲保活</h3><p>数据库连接健康检查可能在驱动网络读取上长时间阻塞,拖住借用连接的请求;不能据此把每个历史503都逐条归因为此缺陷。</p><p>两个模块统一使用有时限的 SELECT 1 健康检查,默认临时网络时限 2 秒;检查结束恢复原连接超时,开启空闲检查和保活。已有普通业务 SQL 超时策略不变。</p><p class="muted">实际 Kingbase 驱动隔离探针:正常检查 12ms,原0ms和原7000ms网络超时均恢复;隔离网络黑洞约2010ms抛出 SocketTimeoutException 并关闭连接。探针不是整个平台可用性测试,后端打包和全量E2E结果另记。</p><small><a href="../../../unreal_tran_api/ut_auth/src/main/java/com/unrealtran/auth/config/BoundedConnectionValidator.java">源码</a> · <a href="../../../unreal_tran_api/ut_tran/src/main/java/com/unrealtran/tran/config/BoundedConnectionValidator.java">另一模块源码</a> · <a href="data/kingbase-validation-probe-result.json">验证证据</a></small></article><article class="panel"><h3>曲线轨道与分量控件的可读性</h3><p>曲线轨道改为按钮后遗漏背景和边框样式,显示为灰底灰字;分量下拉沿用浏览器默认样式并与数值标签重叠。</p><p>补齐整宽暗色轨道按钮、主副文字与选中/悬停/键盘焦点样式;分量下拉使用暗色样式并定位右上。仅修改曲线面板CSS。</p><p class="muted">最终浏览器轮次重新操作轨道、关键帧、五种插值和分量选择并截图;可视效果以最终22与28号截图核对。</p><small><a href="../../../unreal_tran/src/style.css">源码</a> · <a href="screenshots/22-truck-curve-value-five.png">验证证据</a></small></article></div>
  11. <article class="matrix-group" data-group><h3>工程与数据</h3><div class="table-scroll"><table class="matrix"><thead><tr><th>功能 / 真实执行路径</th><th>实现状态</th><th>闭环与边界</th><th>本轮对应修复</th><th>测试证据 / 验收要求</th></tr></thead><tbody><tr data-feature-state="PASS"><td><strong>新建工程</strong><code>project.new</code><small><a href="../../../unreal_tran_web/src/views/content/LegacyModelEditorView.vue">LegacyModelEditorView.vue:118 · createNewProject</a></small></td><td>本轮修复</td><td>宿主创建新项目 ID 并跳转;新建不是清空并覆盖当前工程。</td><td>新建复用正式 create API;创建失败或取消保留原工程。</td><td><span class="badge pass">已验证</span><small><a href="evidence/new-project.json">新建工程取消及失败保留输入;成功创建新ID且不覆盖当前模型</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>新建前后 ID 不同,原工程内容/版本不被覆盖;取消不发创建请求。</small></details></td></tr><tr data-feature-state="PASS"><td><strong>导入装备 GLB</strong><code>project.import-glb</code><small><a href="../../../unreal_tran/src/main.js">main.js:1264 · importModelFile</a></small></td><td>已有实现</td><td>只支持单文件 GLB;上传→登记→解析→最终保存。</td><td>延续导入 busy/失败阻断及稳定资产校验。</td><td><span class="badge pass">已验证</span><small><a href="evidence/30-assets-roundtrip.json">受控模型与外部环境 GLB 上传、JSON 往返和刷新重开</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>选择轻量 GLB,真实模型可见;刷新仍加载同一资产。</small><p><small><b>e2e+api</b>:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>导入工程 JSON</strong><code>project.import-json</code><small><a href="../../../unreal_tran/src/main.js">main.js:2863 · importProjectFile</a></small></td><td>本轮修复</td><td>导入到当前工程,不创建副本;受控引用必须属于当前可用资产。JSON 不含 GLB 字节。</td><td>导入前 materialize 稳定资产引用。</td><td><span class="badge pass">已验证</span><small><a href="evidence/30-assets-roundtrip.json">受控模型与外部环境 GLB 上传、JSON 往返和刷新重开</a> · e2e+api</small><small><a href="evidence/31-invalid-import.json">非法 JSON 与未登记 blob 引用导入失败时保留当前文档</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>同项目导出后再导入,材质/动画/环境不丢;无效或跨项目缺失引用报错。</small><p><small><b>e2e+api</b>:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>手动保存 / Ctrl+S</strong><code>project.save</code><small><a href="../../../unreal_tran/src/main.js">main.js:2748 · saveProject</a></small></td><td>已有实现</td><td>同一工程保存内容和当前视口封面;成功以 API 响应为准。</td><td>保留队列、版本保护和封面失败回退。</td><td><span class="badge pass">已验证</span><small><a href="evidence/30-assets-roundtrip.json">受控模型与外部环境 GLB 上传、JSON 往返和刷新重开</a> · e2e+api</small><small><a href="evidence/32-save-failure-recovery.json">保存请求超时和 409 保留恢复副本,解除故障后可重试</a> · e2e+api</small><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>保存真实 PUT 成功,刷新字段不丢;重复点击不交错。</small><p><small><b>e2e+api</b>:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。</small></p><p><small><b>e2e+api</b>:真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。</small></p><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>30 秒自动保存</strong><code>project.autosave</code><small><a href="../../../unreal_tran/src/main.js">main.js:2122 · bindShellEvents</a></small></td><td>已有实现</td><td>自动保存工程内容;不反复截图更新封面,恢复稿待确认期间暂停。</td><td>导入/封面保存期间阻断重入。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>修改后等待自动保存并刷新;忙碌时不提交半成品。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>修改工程名</strong><code>project.name</code><small><a href="../../../unreal_tran/src/main.js">main.js:457 · projectNameInput</a></small></td><td>已有实现</td><td>输入→失焦/Enter→保存;当前模型工程名。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>改名保存后列表和重新打开一致。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>另存项目 JSON</strong><code>project.export-json</code><small><a href="../../../unreal_tran/src/main.js">main.js:2883 · saveProjectAs</a></small></td><td>已有实现</td><td>下载工程 JSON;不是另建服务端项目,也不内嵌 GLB 文件。</td><td>稳定资产引用保留,临时 blob 地址清除。</td><td><span class="badge pass">已验证</span><small><a href="evidence/30-assets-roundtrip.json">受控模型与外部环境 GLB 上传、JSON 往返和刷新重开</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>下载文件可解析,包含轨道/蓝图/自定义字段,配套资源可重新解析。</small><p><small><b>e2e+api</b>:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>撤销 / Ctrl+Z</strong><code>project.undo</code><small><a href="../../../unreal_tran/src/main.js">main.js:160 · class HistoryStack</a></small></td><td>本轮修复</td><td>最多 60 个历史快照;不是数据库版本回滚。</td><td>异步互斥,失败不移动索引,托管 GLB 快照重新解析。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><small><a href="validation.json">history retains 60 states, truncates redo after edits and ignores duplicate snapshots</a> · unit</small><small><a href="validation.json">history serializes async restores and leaves index unchanged when restoration fails</a> · unit</small><small><a href="validation.json">managed-GLB history downloads the snapshot stable reference before restoring, without rewriting it</a> · unit</small><details><summary>验收要求与证据范围</summary><small>属性/曲线修改撤销;连续点击不并发;下载失败索引与修改保留。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p><p><small><b>unit</b>:60 个快照上限、重复状态忽略及新编辑截断 redo 分支。</small></p><p><small><b>unit</b>:异步互斥、下载失败不移动索引,解除锁后可继续操作。</small></p><p><small><b>unit</b>:受控 GLB 快照先物化再恢复,不把临时 URL 写回快照。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>重做 / Ctrl+Y</strong><code>project.redo</code><small><a href="../../../unreal_tran/src/main.js">main.js:160 · class HistoryStack</a></small></td><td>本轮修复</td><td>撤销后重做;产生新编辑时清掉旧 redo 分支。</td><td>与撤销共用异步恢复保护。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><small><a href="validation.json">history retains 60 states, truncates redo after edits and ignores duplicate snapshots</a> · unit</small><small><a href="validation.json">history serializes async restores and leaves index unchanged when restoration fails</a> · unit</small><small><a href="validation.json">managed-GLB history downloads the snapshot stable reference before restoring, without rewriting it</a> · unit</small><details><summary>验收要求与证据范围</summary><small>重做恢复相同字段及姿态,不回放无效分支。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p><p><small><b>unit</b>:60 个快照上限、重复状态忽略及新编辑截断 redo 分支。</small></p><p><small><b>unit</b>:异步互斥、下载失败不移动索引,解除锁后可继续操作。</small></p><p><small><b>unit</b>:受控 GLB 快照先物化再恢复,不把临时 URL 写回快照。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>异常恢复副本</strong><code>project.recovery</code><small><a href="../../../unreal_tran/src/main.js">main.js:2554 · reconcileApiRecovery</a></small></td><td>本轮修复</td><td>同版本恢复稿需用户确认;旧版本隔离/下载,不静默覆盖服务器。</td><td>恢复稿重新解析受控资源;指纹忽略对象键顺序,避免已保存页面刷新误生恢复稿。</td><td><span class="badge pass">已验证</span><small><a href="evidence/60-project-recovery.json">真实未保存稿同版本恢复并显式保存;旧版本恢复稿下载隔离保留</a> · e2e+api</small><small><a href="validation.json">beforeunload recovery does not create a draft for key order alone, but preserves real unsaved changes</a> · unit</small><details><summary>验收要求与证据范围</summary><small>同版本恢复可见;旧版本保留/下载;主动保存前不自动 PUT。</small><p><small><b>e2e+api</b>:通过真实beforeunload创建未保存稿;同版恢复后仅显式保存落库;旧版只下载隔离,不自动覆盖服务端。丢弃/跨标签竞态另由既有恢复合同测试覆盖。</small></p><p><small><b>unit</b>:同语义对象键顺序不产生假恢复稿;真正修改仍保留。不包含全部恢复/隔离/下载 UI 分支。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>保存/发布版本冲突</strong><code>project.conflict</code><small><a href="../../../unreal_tran/src/model-content-api.js">model-content-api.js:1025 · queueSave</a></small></td><td>已有实现</td><td>409 阻断;恢复稿保留。</td><td>发布封面队列同样遵守冲突保护。</td><td><span class="badge pass">已验证</span><small><a href="evidence/32-save-failure-recovery.json">保存请求超时和 409 保留恢复副本,解除故障后可重试</a> · e2e+api</small><small><a href="validation.json">API conflict leaves publication failed and releases the cover guard</a> · unit</small><details><summary>验收要求与证据范围</summary><small>定向模拟 409,无后续发布请求,不误报成功。</small><p><small><b>e2e+api</b>:真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。</small></p><p><small><b>unit</b>:409 分支不误报已发布并释放 busy 标记;模拟 API。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>查看/编辑/新增/发布权限</strong><code>project.permissions</code><small><a href="../../../unreal_tran_web/src/features/editors/model/legacy-iframe-permissions.ts">legacy-iframe-permissions.ts:32 · installLegacyModelPermissions</a></small></td><td>本轮修复</td><td>按 content.model.* 权限,不按 teacher/admin 身份推断写权限;只读仍能搜索、选择原生动画和键盘激活预览。</td><td>新建接真实 create 能力;只发布可发布已保存版本;修复查看控件键盘事件误拦截。</td><td><span class="badge pass">已验证</span><small><a href="evidence/permissions.json">管理员只读权限:编辑、新建、导入、保存发布均不可越权</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>只读查看操作可用且无内容写请求;不可编辑/保存;publisher 不上传/PUT,正常发布已有版本。</small><p><small><b>e2e+api</b>:管理员只读UI、真实键盘搜索、原生片段切换与Enter播放/暂停、预览无内容写请求及创建403;纯publisher无需update的发布流程由独立权限合同回归补充。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>离开/切角色未保存确认</strong><code>project.leave</code><small><a href="../../../unreal_tran_web/src/views/content/LegacyModelEditorView.vue">LegacyModelEditorView.vue:147 · confirmLeave</a></small></td><td>已有实现</td><td>取消留在当前页;保存失败不得离开;上传/保存/发布忙时保留状态。</td><td>新建也复用现有未保存确认。</td><td><span class="badge pass">已验证</span><small><a href="evidence/43-builtin-environments-tree.json">补充环境与树:内置三环境保存重开、节点计数与折叠展开</a> · e2e+api</small><small><a href="evidence/52-leave.json">未保存离开:关闭确认保留工作、保存失败留在原页、重试保存后离开</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>取消、放弃、保存失败与 busy 分别验证,没有误清 dirty。</small><p><small><b>e2e+api</b>:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。</small></p></details></td></tr></tbody></table></div></article><article class="matrix-group" data-group><h3>资源库与场景树</h3><div class="table-scroll"><table class="matrix"><thead><tr><th>功能 / 真实执行路径</th><th>实现状态</th><th>闭环与边界</th><th>本轮对应修复</th><th>测试证据 / 验收要求</th></tr></thead><tbody><tr data-feature-state="PASS"><td><strong>资源库浏览 / 选择装备</strong><code>resource.catalog</code><small><a href="../../../unreal_tran/src/main.js">main.js:1383 · renderAssets</a></small></td><td>本轮修复</td><td>切换装备可能应用其基准时间轴/蓝图;不是把第二个主装备追加进当前模型。</td><td>修复单节点选择器误用导致启动报错;忙碌期间禁止切换资源。</td><td><span class="badge pass">已验证</span><small><a href="evidence/41-resource-search-switch.json">补充资源库:搜索清空、真实卡片切换与刷新保留</a> · e2e+api</small><small><a href="validation.json">resource catalog startup renders all model/environment cards and binds every action with a real DOM</a> · unit</small><details><summary>验收要求与证据范围</summary><small>完整资源库 DOM 初始化、卡片事件、空目录启动正常;切换实际几何可见,保存后资源一致。</small><p><small><b>e2e+api</b>:真实搜索与资源卡片点击、服务端保存、刷新后原模型网格;副本独立登记待清理。</small></p><p><small><b>unit</b>:真实 DOM 渲染、卡片绑定、空目录及 busy 保护;不包含 GLB 网络加载。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>资源搜索</strong><code>resource.search</code><small><a href="../../../unreal_tran/src/main.js">main.js:1467 · applyAssetSearch</a></small></td><td>已有实现</td><td>按资源名称/关键词过滤现有目录,不搜索服务器全站。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/41-resource-search-switch.json">补充资源库:搜索清空、真实卡片切换与刷新保留</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>关键字命中、空结果与清空恢复。</small><p><small><b>e2e+api</b>:真实搜索与资源卡片点击、服务端保存、刷新后原模型网格;副本独立登记待清理。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>内置车间 / 野外 / 装备车库</strong><code>environment.builtin</code><small><a href="../../../unreal_tran/src/main.js">main.js:789 · resetEnvironmentPlaceholder</a></small></td><td>已有实现</td><td>车间/野外为程序化环境;车库为随包 GLB。</td><td>保留真实 GLB 和占位环境来源区别。</td><td><span class="badge pass">已验证</span><small><a href="evidence/43-builtin-environments-tree.json">补充环境与树:内置三环境保存重开、节点计数与折叠展开</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>三种切换与重新打开可重现相应环境。</small><p><small><b>e2e+api</b>:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>导入外部车间 / 野外 GLB</strong><code>environment.external</code><small><a href="../../../unreal_tran/src/main.js">main.js:1028 · loadEnvironmentSceneFile</a></small></td><td>本轮修复</td><td>一个环境根;受控 MODEL_FILE 资产 metadata.usage=environment,与主装备独立。</td><td>上传、最终保存、JSON 与刷新恢复稳定引用;失败阻断半提交。</td><td><span class="badge pass">已验证</span><small><a href="evidence/30-assets-roundtrip.json">受控模型与外部环境 GLB 上传、JSON 往返和刷新重开</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>小 GLB 上传后主装备不被替换;环境刷新仍可见且资产引用一致。</small><p><small><b>e2e+api</b>:真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>模型加载进度 / 失败 / 重试</strong><code>resource.loading</code><small><a href="../../../unreal_tran_web/src/views/content/LegacyModelEditorView.vue">LegacyModelEditorView.vue:33 · installLegacyModelIframeLoadingScope</a></small></td><td>已有实现</td><td>局部加载状态;错误短提示,中性失败状态可重试。</td><td>复用前轮加载范围与错误消息修复。</td><td><span class="badge pass">已验证</span><small><a href="evidence/63-loading-publish-preflight.json">受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>资源失败不无限转圈;重试恢复;无凭据泄露。</small><p><small><b>e2e+api</b>:真实受控下载定向503→中性失败与禁止编辑→解除故障后UI重试成功;预检面板开关不写项目,错误资源JSON在替换当前模型之前被拒绝。服务端发布时code/URI一致性拒绝由ContentProjectServiceTest合同回归覆盖,未把面板绿标代替服务端校验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>场景树节点与计数</strong><code>tree.browse</code><small><a href="../../../unreal_tran/src/main.js">main.js:1925 · buildSceneTree</a></small></td><td>现有边界</td><td>树行上限 220;统计节点总数不等于当前展开行数。</td><td>无本轮容量重构。</td><td><span class="badge pass">已验证</span><small><a href="evidence/43-builtin-environments-tree.json">补充环境与树:内置三环境保存重开、节点计数与折叠展开</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>模型/环境节点可达,计数说明不当作全部节点已经逐项验收。</small><p><small><b>e2e+api</b>:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>节点展开 / 折叠</strong><code>tree.expand</code><small><a href="../../../unreal_tran/src/main.js">main.js:1925 · buildSceneTree</a></small></td><td>已有实现</td><td>当前界面浏览状态;无须持久化展开布局。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/43-builtin-environments-tree.json">补充环境与树:内置三环境保存重开、节点计数与折叠展开</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>展开和折叠子级不修改模型对象。</small><p><small><b>e2e+api</b>:真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>场景树搜索</strong><code>tree.search</code><small><a href="../../../unreal_tran/src/main.js">main.js:1925 · buildSceneTree</a></small></td><td>已有实现</td><td>搜索当前载入对象,不新增/删除对象。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>搜索节点后选中正确对象,清空恢复树。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>显示 / 隐藏对象</strong><code>tree.visibility</code><small><a href="../../../unreal_tran/src/main.js">main.js:1925 · buildSceneTree</a></small></td><td>本轮修复</td><td>对象 visible 保存;隐藏祖先的子对象不接受射线拾取。</td><td>拾取与高亮统一检查祖先可见性。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><small><a href="validation.json">visible child under a hidden ancestor cannot be picked or highlighted; trigger aliases include ancestors</a> · unit</small><details><summary>验收要求与证据范围</summary><small>隐藏父级后不能点到子级,保存重开仍隐藏。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p><p><small><b>unit</b>:共用可见性和祖先别名函数;鼠标事件另由 E2E 验证。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>整体 / 部件级选择</strong><code>selection.scope</code><small><a href="../../../unreal_tran/src/main.js">main.js:1938 · setSelectionScope</a></small></td><td>已有实现</td><td>整体作用主装备根;部件作用实际节点。</td><td>保留当前选择层级合同。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>点击可见 mesh,整体/部件切换选择目标不同。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>树 / 视口 / 属性选择联动</strong><code>selection.sync</code><small><a href="../../../unreal_tran/src/main.js">main.js:1947 · selectObject</a></small></td><td>本轮修复</td><td>显示实际对象并更新辅助框;环境也是可编辑对象。</td><td>关闭轮廓后重选不恢复辅助框。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>三处名称/对象 ID 一致,重选后轮廓状态保持。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr></tbody></table></div></article><article class="matrix-group" data-group><h3>三维视图与操作</h3><div class="table-scroll"><table class="matrix"><thead><tr><th>功能 / 真实执行路径</th><th>实现状态</th><th>闭环与边界</th><th>本轮对应修复</th><th>测试证据 / 验收要求</th></tr></thead><tbody><tr data-feature-state="PASS"><td><strong>鼠标旋转 / 平移 / 缩放视角</strong><code>view.orbit</code><small><a href="../../../unreal_tran/src/main.js">main.js:2 · OrbitControls</a></small></td><td>已有实现</td><td>当前三维相机;不是模型变换。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>鼠标操作改变镜头但不改变对象局部坐标。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>聚焦选中 / F</strong><code>view.focus</code><small><a href="../../../unreal_tran/src/main.js">main.js:2272 · fitCamera</a></small></td><td>已有实现</td><td>按当前对象包围盒定位相机。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>小模型/部件聚焦后仍可见,不被裁剪。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>移动工具 / W</strong><code>view.move</code><small><a href="../../../unreal_tran/src/main.js">main.js:2234 · setTransformMode</a></small></td><td>本轮修复</td><td>拖拽编辑对象局部位置,保存后重开一致。</td><td>动画姿态下更新基值只扣实际偏移。</td><td><span class="badge pass">已验证</span><small><a href="evidence/51-gizmos.json">真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开</a> · e2e+runtime-readback</small><details><summary>验收要求与证据范围</summary><small>移动后保存、刷新及动画再播放不漂移。</small></details></td></tr><tr data-feature-state="PASS"><td><strong>旋转工具 / E</strong><code>view.rotate</code><small><a href="../../../unreal_tran/src/main.js">main.js:2234 · setTransformMode</a></small></td><td>本轮修复</td><td>对象旋转;与当前时间轴旋转叠加需要一致。</td><td>统一动画基值处理。</td><td><span class="badge pass">已验证</span><small><a href="evidence/51-gizmos.json">真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开</a> · e2e+runtime-readback</small><details><summary>验收要求与证据范围</summary><small>旋转后保存/撤销/重做姿态一致。</small></details></td></tr><tr data-feature-state="PASS"><td><strong>缩放工具 / R</strong><code>view.scale</code><small><a href="../../../unreal_tran/src/main.js">main.js:2234 · setTransformMode</a></small></td><td>已有实现</td><td>对象缩放持久化;时间轴没有缩放轨道 UI。</td><td>无新增缩放动画能力。</td><td><span class="badge pass">已验证</span><small><a href="evidence/51-gizmos.json">真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开</a> · e2e+runtime-readback</small><details><summary>验收要求与证据范围</summary><small>对象缩放保存和重开正确。</small></details></td></tr><tr data-feature-state="PASS"><td><strong>网格开关</strong><code>view.grid</code><small><a href="../../../unreal_tran/src/main.js">main.js:2283 · toggleGrid</a></small></td><td>已有实现</td><td>临时视图选项,不要求写入工程。</td><td>非持久化不计保存缺陷。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>开关只影响辅助网格,不改变模型。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>PBR 光照开关</strong><code>view.pbr</code><small><a href="../../../unreal_tran/src/main.js">main.js:2236 · handleView</a></small></td><td>已有实现</td><td>当前照明预览选项;不是批量材质编辑。</td><td>非持久化不计保存缺陷。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>开关改变显示,物体材质字段不被覆盖。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>线框开关</strong><code>view.wireframe</code><small><a href="../../../unreal_tran/src/main.js">main.js:2236 · handleView</a></small></td><td>已有实现</td><td>当前视图选项;不承诺保存到工程。</td><td>非持久化不计保存缺陷。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>线框开关恢复正常着色。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>选中轮廓开关</strong><code>view.outline</code><small><a href="../../../unreal_tran/src/main.js">main.js:2236 · handleView</a></small></td><td>本轮修复</td><td>当前会话偏好,进出预览后保持;不要求跨重载存储。</td><td>重选时不重新泄露轮廓。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>关闭→重选→预览→退出,轮廓仍关闭。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>透视视角按钮</strong><code>view.perspective</code><small><a href="../../../unreal_tran/src/main.js">main.js:2236 · handleView</a></small></td><td>现有边界</td><td>重置透视观察角度;当前没有正交视角菜单。</td><td>不把临时视图状态当作保存缺陷。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>点击后相机和聚焦目标正常。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>下载视口截图</strong><code>view.snapshot</code><small><a href="../../../unreal_tran/src/main.js">main.js:3092 · downloadSnapshot</a></small></td><td>已有实现</td><td>当前 canvas PNG,可包含编辑辅助元素;保存封面是独立截图流程。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>PNG 下载可打开,内容与当前视口对应。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>底部页签 / Tab / 面板高度</strong><code>view.panels</code><small><a href="../../../unreal_tran/src/main.js">main.js:2215 · switchBottomMode</a></small></td><td>已有实现</td><td>时间轴、蓝图、曲线、日志切换;拖分割条只调整当前工作区。</td><td>曲线入口接真实数据。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>各页签显示正确内容,调整高度后画布正确 resize。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>进入 / 退出运行预览</strong><code>view.preview</code><small><a href="../../../unreal_tran/src/main.js">main.js:2284 · togglePreview</a></small></td><td>本轮修复</td><td>真实当前三维场景;隐藏辅助工具,退出不丢编辑状态。</td><td>进入显式派发 auto;退出停止运行并恢复轮廓策略。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-events.json">已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发</a> · e2e</small><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>进入/退出与 Esc,三维仍可见,无辅助框泄漏。</small><p><small><b>e2e</b>:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。</small></p><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>预览播放 / 前后导航</strong><code>view.preview-step</code><small><a href="../../../unreal_tran/src/main.js">main.js:2122 · bindShellEvents</a></small></td><td>现有边界</td><td>播放运行蓝图;前后按钮当前按时间轴 ±2 秒,不是按业务工序跳转。</td><td>无新增业务工序导航。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>播放触发真实流程;前后跳时与时间轴一致。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr></tbody></table></div></article><article class="matrix-group" data-group><h3>对象属性与扩展标记</h3><div class="table-scroll"><table class="matrix"><thead><tr><th>功能 / 真实执行路径</th><th>实现状态</th><th>闭环与边界</th><th>本轮对应修复</th><th>测试证据 / 验收要求</th></tr></thead><tbody><tr data-feature-state="PASS"><td><strong>对象名称</strong><code>property.name</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>已有实现</td><td>修改当前节点名,标识保持稳定。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>树和属性同步,保存重开名称保留。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>对象标识 / 状态说明</strong><code>property.identity</code><small><a href="../../../unreal_tran/src/main.js">main.js:1958 · renderInspector</a></small></td><td>本轮修复</td><td>标识只读;可见性含祖先状态,阴影取实际castShadow;编辑能力由宿主权限注入。</td><td>不再固定显示“可见/投射阴影”,补宿主可编辑状态钩子。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><small><a href="validation.json">inspector state tags reflect ancestor visibility and actual shadow flags, with a host editability hook</a> · unit</small><details><summary>验收要求与证据范围</summary><small>标识不可编辑;选中对象、隐藏状态、阴影及只读权限标签一致。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p><p><small><b>unit</b>:真实属性 DOM 显示隐藏/阴影状态,并提供宿主权限标签 hook;不伪称此单测完成会话鉴权。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>位置 XYZ 数值</strong><code>property.position</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>本轮修复</td><td>局部坐标;动画当前帧下编辑也能生成正确基值。</td><td>中性姿态与实际应用偏移统一。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>三个轴编辑、保存重开、动画回放一致。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>旋转 XYZ 数值</strong><code>property.rotation</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>本轮修复</td><td>输入角度转弧度存储,显示角度。</td><td>多轨旋转基值不重复扣除。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>度数显示与存储/播放的弧度一致。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>缩放 XYZ 数值</strong><code>property.scale</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>已有实现</td><td>对象当前缩放,不添加新的缩放轨道。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>非均匀缩放可保存和重开。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>材质基础色</strong><code>property.color</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>现有边界</td><td>只编辑当前对象第一个材质槽;共享材质可能影响共享该实例的网格。</td><td>界面明确材质槽 1/N。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>颜色修改、保存重开对应当前槽;不宣称所有槽可编辑。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>材质金属度</strong><code>property.metalness</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>现有边界</td><td>当前首槽 PBR 参数 0~1。</td><td>标明材质槽范围。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>拖动参数有效,保存重开值一致。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>材质粗糙度</strong><code>property.roughness</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>现有边界</td><td>当前首槽 PBR 参数 0~1。</td><td>标明材质槽范围。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>参数与当前槽持久化一致。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>材质透明度</strong><code>property.opacity</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>现有边界</td><td>当前首槽;联动 transparent/depthWrite。</td><td>保留实际透明度保存字段。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>透明效果与重开结果一致。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>自定义资源编码</strong><code>property.code</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>本轮修复</td><td>对象 customProperties.resourceCode,不是服务器资产主键。</td><td>输入真正回写、保存、恢复及撤销。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><small><a href="validation.json">custom properties and extension labels survive actual capture, project JSON and object restore</a> · unit</small><details><summary>验收要求与证据范围</summary><small>编辑、清空、重选、JSON 往返、刷新均一致。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p><p><small><b>unit</b>:真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>自定义运行状态</strong><code>property.status</code><small><a href="../../../unreal_tran/src/main.js">main.js:1996 · bindInspectorEvents</a></small></td><td>本轮修复</td><td>NORMAL/SERVICE 标签,不会发起真实设备控制。</td><td>真正写回对象,首次变更可撤销。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><small><a href="validation.json">custom properties and extension labels survive actual capture, project JSON and object restore</a> · unit</small><details><summary>验收要求与证据范围</summary><small>两状态切换及刷新保留。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p><p><small><b>unit</b>:真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>流程绑定说明</strong><code>property.binding</code><small><a href="../../../unreal_tran/src/main.js">main.js:1958 · renderInspector</a></small></td><td>现有边界</td><td>只读显示模板/时间轴名称,不是教学任务的设备或物联网绑定。</td><td>无本轮业务绑定改造。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>只读,不将其当作任务绑定操作验收。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>组件页内置能力说明</strong><code>component.inspect</code><small><a href="../../../unreal_tran/src/main.js">main.js:1975 · renderComponents</a></small></td><td>现有边界</td><td>变换、场景节点、渲染等派生说明,没有通用组件启停系统。</td><td>区分内置说明与自定义标记。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>显示与对象类型一致,不虚报可执行组件配置。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>添加扩展标记</strong><code>component.tag</code><small><a href="../../../unreal_tran/src/main.js">main.js:1975 · renderComponents</a></small></td><td>本轮澄清</td><td>只保存名称标签;没有脚本、启停、运行时行为。</td><td>从“添加组件”改为“扩展标记,仅保存标签”。</td><td><span class="badge pass">已验证</span><small><a href="evidence/properties.json">对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</a> · e2e+api</small><small><a href="validation.json">custom properties and extension labels survive actual capture, project JSON and object restore</a> · unit</small><details><summary>验收要求与证据范围</summary><small>新增标签保存/重开;不得声称已启用新行为。</small><p><small><b>e2e+api</b>:真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。</small></p><p><small><b>unit</b>:真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。</small></p></details></td></tr></tbody></table></div></article><article class="matrix-group" data-group><h3>时间轴与曲线</h3><div class="table-scroll"><table class="matrix"><thead><tr><th>功能 / 真实执行路径</th><th>实现状态</th><th>闭环与边界</th><th>本轮对应修复</th><th>测试证据 / 验收要求</th></tr></thead><tbody><tr data-feature-state="PASS"><td><strong>播放 / 暂停 / Space</strong><code>timeline.play</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:393 · play()</a></small></td><td>已有实现</td><td>播放当前编辑时间轴;原生 GLB 动画单独控制。</td><td>停止清理与时间同步由本轮补强。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>播放进度/真实对象姿态变化,暂停停在当前帧。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>停止</strong><code>timeline.stop</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:429 · stop()</a></small></td><td>已有实现</td><td>停止并回到起始时间,按起始帧应用动画。</td><td>无本轮语义扩展。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>按钮停止后不再自行前进。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>循环开关</strong><code>timeline.loop</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:198 · #bindEvents</a></small></td><td>本轮修复</td><td>循环设置随 timeline 保存;不循环到达终点只完成一次。</td><td>循环变更进入历史/dirty。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>开关、保存重开、到末尾/循环边界正确。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>上一 / 下一关键帧</strong><code>timeline.key-nav</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:232 · #onClick</a></small></td><td>已有实现</td><td>按时间轴关键帧时间定位。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>多个轨道时跳到正确相邻关键时刻。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>拖播放头 / 点击刻度</strong><code>timeline.seek</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:263 · #onPointerDown</a></small></td><td>本轮修复</td><td>实时求值当前帧;键盘左右移动一帧,Shift 移动一秒。</td><td>拖动补发 timechange,解绑指针监听。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-tool-supplement.json">补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>时间码、曲线和视口姿态同步。</small><p><small><b>e2e+runtime-read</b>:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>添加轨道</strong><code>timeline.add-track</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:471 · addTrack(</a></small></td><td>已有实现</td><td>当前主装备节点的变换轨道。</td><td>无新增轨道类型。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>增加后可绑定节点并保存。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>删除轨道</strong><code>timeline.remove-track</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:495 · removeTrack(</a></small></td><td>本轮修复</td><td>删除后不再保留该轨道施加的旧姿态。</td><td>宿主恢复此前作用的属性基值。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>删除即时复原,再保存/重开一致。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>修改轨道目标节点</strong><code>timeline.target</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:506 · updateSelectedTrack</a></small></td><td>本轮修复</td><td>用稳定对象标识绑定,不靠同名第一项。</td><td>重绑清理旧目标的应用姿态。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><small><a href="validation.json">changing a binding resets the former target and keeps manual transform edits as base</a> · unit</small><details><summary>验收要求与证据范围</summary><small>从 A 改为 B,A 复原,B 播放。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p><p><small><b>unit</b>:轨道重绑后旧目标复位,手动变换成为新基值;不假称鼠标拖动已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>选择位置 / 旋转属性</strong><code>timeline.property</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:506 · updateSelectedTrack</a></small></td><td>已有实现</td><td>位置 XYZ 向量、旋转 X/Y/Z;没有缩放轨道 UI。</td><td>保留当前实际能力。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>属性切换后关键帧类型和播放一致。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>轨道静音</strong><code>timeline.mute</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:232 · #onClick</a></small></td><td>本轮修复</td><td>仅忽略当前轨道,不关闭其他轨道。</td><td>不再停留旧姿态或保存时重复扣值。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>静音/恢复后实际姿态与重开一致。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>记录当前姿态关键帧</strong><code>timeline.record</code><small><a href="../../../unreal_tran/src/main.js">main.js:2276 · addKeyframeFromSelection</a></small></td><td>本轮修复</td><td>记录相对对象基值的当前值。</td><td>与多轨实际应用/保存采用同一基值。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-tool-supplement.json">补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>操作对象后记录,回放命中相同姿态。</small><p><small><b>e2e+runtime-read</b>:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>双击新增关键帧</strong><code>timeline.add-key</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:255 · #onDoubleClick</a></small></td><td>已有实现</td><td>在轨道对应时刻创建/更新关键帧。</td><td>时间碰撞保留当前编辑帧。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>新增后节点可选,时间/数值可保存。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>删除关键帧 / Delete</strong><code>timeline.delete-key</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:584 · deleteSelected</a></small></td><td>已有实现</td><td>删除选中的关键帧;输入框编辑时不截获删除键。</td><td>删除和监听清理回归。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>删除后曲线和播放变化,撤销可恢复。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>关键帧拖动 / Alt 取消吸附</strong><code>timeline.drag-key</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:263 · #onPointerDown</a></small></td><td>本轮修复</td><td>默认 1/30 秒吸附;重叠时合并,保留正在编辑帧。</td><td>拖动时间同步,碰撞处理确定。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>拖动/重叠/Alt 行为和保存后时间正确。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>时间轴缩放</strong><code>timeline.zoom</code><small><a href="../../../unreal_tran/src/timeline.js">timeline.js:451 · setZoom</a></small></td><td>已有实现</td><td>显示缩放随 timeline 记录;不改变时长/关键帧数值。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>缩放不改变动作内容。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>多轨组合与保存基值</strong><code>timeline.multitrack</code><small><a href="../../../unreal_tran/src/model-editor-state.js">model-editor-state.js:12 · applyEditorTimelinePose</a></small></td><td>本轮修复</td><td>不同属性组合;同对象同属性最后有效轨道生效。</td><td>求值、手工编辑基值、序列化一致。</td><td><span class="badge pass">已验证</span><small><a href="validation.json">multiple tracks on one property use last effective value; capture subtracts it only once</a> · unit</small><small><a href="validation.json">changing a binding resets the former target and keeps manual transform edits as base</a> · unit</small><details><summary>验收要求与证据范围</summary><small>两轨同属性、静音、删轨、重绑、重开无漂移。</small><p><small><b>unit</b>:调用实际 apply/capture/update 基值方法;验证同属性最后有效轨道、静音/删除后中性姿态,偏移只扣一次。</small></p><p><small><b>unit</b>:轨道重绑后旧目标复位,手动变换成为新基值;不假称鼠标拖动已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>载入装备基准动作</strong><code>timeline.baseline</code><small><a href="../../../unreal_tran/src/main.js">main.js:3058 · loadBaselineAnimation</a></small></td><td>现有边界</td><td>匹配部件后直接替换当前时间轴/蓝图;当前没有单独确认框,不是任意维修流程自动生成。</td><td>保持当前装备限定;无匹配只提示,不改工程。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-tool-supplement.json">补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>匹配时载入/保存/重开;无匹配时保留原数据并给出提示。</small><p><small><b>e2e+runtime-read</b>:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>GLB 原生动画选择 / 播放</strong><code>timeline.native</code><small><a href="../../../unreal_tran/src/main.js">main.js:1715 · selectNativeAnimation</a></small></td><td>已有实现</td><td>真实 GLB 自带片段;保存选择索引,不是蓝图 clip 字段。</td><td>无片段时禁用。</td><td><span class="badge pass">已验证</span><small><a href="evidence/viewport.json">场景树搜索、可见性、选择、视口工具、原生动画与截图</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>狐狸实际动画播放/暂停,选择保存后重开一致。</small><p><small><b>e2e</b>:树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>曲线选择轨道 / 关键帧</strong><code>timeline.curve</code><small><a href="../../../unreal_tran/src/model-curve-editor.js">model-curve-editor.js:5 · class ModelCurveEditor</a></small></td><td>本轮修复</td><td>曲线与时间轴共用一份轨道和关键帧数据。</td><td>移除固定 SVG 假数据。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><small><a href="validation.json">curve edits real scalar key values, time and interpolation, persisting through document reload</a> · unit</small><details><summary>验收要求与证据范围</summary><small>实际轨道名和点数匹配时间轴,点击同步当前帧。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p><p><small><b>unit</b>:真实曲线控件与 TimelineEditor,标量编辑与文档往返。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>曲线编辑时间</strong><code>curve.time</code><small><a href="../../../unreal_tran/src/model-curve-editor.js">model-curve-editor.js:30 · change(input)</a></small></td><td>本轮修复</td><td>更新实际 key.time,约束在时间轴时长内。</td><td>调用 timeline.updateKeyframe 并保持编辑目标。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><small><a href="validation.json">curve edits real scalar key values, time and interpolation, persisting through document reload</a> · unit</small><details><summary>验收要求与证据范围</summary><small>改时间后重排、撤销、JSON 往返一致。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p><p><small><b>unit</b>:真实曲线控件与 TimelineEditor,标量编辑与文档往返。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>曲线编辑标量 / XYZ 数值</strong><code>curve.value</code><small><a href="../../../unreal_tran/src/model-curve-editor.js">model-curve-editor.js:30 · change(input)</a></small></td><td>本轮修复</td><td>修改实际关键帧值,向量编辑保留其他分量。</td><td>无效空值拒绝提交。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><small><a href="validation.json">curve edits real scalar key values, time and interpolation, persisting through document reload</a> · unit</small><small><a href="validation.json">curve vector editing preserves other components and selected track; invalid values do not mutate</a> · unit</small><details><summary>验收要求与证据范围</summary><small>标量和向量都驱动真实姿态并保存。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p><p><small><b>unit</b>:真实曲线控件与 TimelineEditor,标量编辑与文档往返。</small></p><p><small><b>unit</b>:向量其它分量保留,当前轨道、非法值保护;不包含显示轴切换或可视像素验收。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>曲线插值</strong><code>curve.easing</code><small><a href="../../../unreal_tran/src/model-curve-editor.js">model-curve-editor.js:30 · change(input)</a></small></td><td>本轮修复</td><td>支持线性、平滑、缓入、缓出、阶梯;没有 Bezier 切线 UI。</td><td>阶梯插值与已有下游时间轴求值一致。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-timeline-curve.json">时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</a> · e2e+runtime-read</small><small><a href="validation.json">curve edits real scalar key values, time and interpolation, persisting through document reload</a> · unit</small><details><summary>验收要求与证据范围</summary><small>修改插值改变中间帧,重开保留。</small><p><small><b>e2e+runtime-read</b>:真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。</small></p><p><small><b>unit</b>:真实曲线控件与 TimelineEditor,标量编辑与文档往返。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>曲线 XYZ 分量显示</strong><code>curve.axis</code><small><a href="../../../unreal_tran/src/model-curve-editor.js">model-curve-editor.js:30 · change(input)</a></small></td><td>已有实现</td><td>改变图上显示分量,不改另外两轴的数据。</td><td>当前实际向量轨道才出现。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-tool-supplement.json">补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>切分量显示不同曲线,数值不被改写。</small><p><small><b>e2e+runtime-read</b>:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。</small></p></details></td></tr></tbody></table></div></article><article class="matrix-group" data-group><h3>蓝图与交互反馈</h3><div class="table-scroll"><table class="matrix"><thead><tr><th>功能 / 真实执行路径</th><th>实现状态</th><th>闭环与边界</th><th>本轮对应修复</th><th>测试证据 / 验收要求</th></tr></thead><tbody><tr data-feature-state="PASS"><td><strong>节点库搜索 / 拖入节点</strong><code>blueprint.palette</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:287 · _renderPalette</a></small></td><td>已有实现</td><td>当前七类节点:触发、时间轴、等待、高亮、提示、条件、完成。</td><td>不新增任意脚本节点。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-tool-supplement.json">补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>搜索、拖入后节点类型和参数可保存。</small><p><small><b>e2e+runtime-read</b>:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>添加节点按钮</strong><code>blueprint.add</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:257 · _bind()</a></small></td><td>已有实现</td><td>工具栏默认添加提示节点;其他类型来自节点库。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-tool-supplement.json">补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>新增进入画布、历史与 JSON。</small><p><small><b>e2e+runtime-read</b>:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>节点标题 / 参数编辑</strong><code>blueprint.parameters</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:431 · _renderInspector</a></small></td><td>已有实现</td><td>按节点类型提供数字、文字、枚举、复选框。</td><td>保留数值边界与真实数据写回。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>改参数与标题后重开保留。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>节点拖动 / 多选框选</strong><code>blueprint.move</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:566 · _onViewportPointerDown</a></small></td><td>已有实现</td><td>节点布局随蓝图 JSON 保存。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>多选移动位置正确,撤销恢复。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>连接 / 替换 / 删除执行线</strong><code>blueprint.connect</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:767 · connect(</a></small></td><td>本轮修复</td><td>单输出重连替换;允许多个来源汇聚同一输入。</td><td>不再清掉同一输入的其他合法来源。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>true/false 汇聚保留两条,替换输出只影响该线。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>删除节点 / 连线</strong><code>blueprint.delete</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:786 · deleteSelection</a></small></td><td>已有实现</td><td>删除节点一并清理相关边。</td><td>复制/剪切使用同一图数据合同。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>无悬空边;撤销恢复完整图。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>复制 / 剪切 / 粘贴</strong><code>blueprint.copy</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:714 · copySelection</a></small></td><td>本轮修复</td><td>Ctrl/Cmd+C/X/V;复制选区内部边,不复制指向外部的边。</td><td>新节点 ID 和内部连线同步生成,阻止快捷键冒泡。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>副本内部连接正确,不误删外部对象。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>平移 / 缩放 / 适应画布</strong><code>blueprint.canvas</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:801 · frameAll</a></small></td><td>已有实现</td><td>蓝图画布浏览;不是三维相机。</td><td>无本轮专门改动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-tool-supplement.json">补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>滚轮、Space 拖动和适应可见全部节点。</small><p><small><b>e2e+runtime-read</b>:真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>运行 / F5</strong><code>blueprint.run</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:871 · async run(</a></small></td><td>本轮修复</td><td>在当前模型编辑器驱动真实场景;有 200 步循环上限。</td><td>条件与等待流程回归。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>执行高亮、动作、反馈;循环图可终止不挂死。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>停止运行</strong><code>blueprint.stop</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:997 · stop(</a></small></td><td>本轮修复</td><td>停止中断挂起等待,旧运行不覆盖新运行状态。</td><td>AbortSignal 贯穿宿主动作与高亮清理。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>等待/动画中停止及时退出,无迟到完成提示。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>重置执行</strong><code>blueprint.reset</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:1014 · resetExecution</a></small></td><td>已有实现</td><td>复位执行状态、时间轴和高亮;保留蓝图编辑内容。</td><td>高亮恢复原材质。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>运行后重置,进度归零且节点图不丢。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>点击触发目标</strong><code>blueprint.click</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:933 · async trigger(</a></small></td><td>本轮修复</td><td>匹配事件和目标 ID/名称/祖先别名;空目标可通配。</td><td>不再点击 B 触发 A。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-events.json">已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>两个不同目标分别点击,只运行匹配分支。</small><p><small><b>e2e</b>:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>双击触发目标</strong><code>blueprint.double-click</code><small><a href="../../../unreal_tran/src/main.js">main.js:2256 · pickObject</a></small></td><td>本轮修复</td><td>双击独立派发 double-click,与单击区分。</td><td>增加真实视口双击派发并抑制待发单击。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-events.json">已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>双击只触发目标的双击分支。</small><p><small><b>e2e</b>:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>自动触发</strong><code>blueprint.auto</code><small><a href="../../../unreal_tran/src/main.js">main.js:2284 · togglePreview</a></small></td><td>本轮修复</td><td>仅进入预览显式派发 auto,不把每次单击当 auto。</td><td>事件匹配与进入预览联动。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-events.json">已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发</a> · e2e</small><details><summary>验收要求与证据范围</summary><small>进入预览触发一次,普通点击不重放自动分支。</small><p><small><b>e2e</b>:执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>播放时间轴节点</strong><code>blueprint.timeline</code><small><a href="../../../unreal_tran/src/main.js">main.js:2024 · playTimelineForBlueprint</a></small></td><td>本轮修复</td><td>播放当前唯一时间轴,动作名称仅描述;支持起始时间、速度、等待。</td><td>起始末帧不反跳零,终止可取消。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>起始时间和速度实际生效,等待与不等待分支正确。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>等待节点</strong><code>blueprint.wait</code><small><a href="../../../unreal_tran/src/blueprint.js">blueprint.js:1 · NODE_TYPES</a></small></td><td>已有实现</td><td>指定毫秒等待;可被停止取消。</td><td>异步停止及时结束。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>等待期间停止不会继续执行后续节点。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>高亮节点 / 呼吸效果</strong><code>blueprint.highlight</code><small><a href="../../../unreal_tran/src/main.js">main.js:2052 · highlightPart</a></small></td><td>本轮修复</td><td>准确命中可见对象;同名歧义要求标识;没有可高亮材质则报错。</td><td>拒绝错误整机回退,真实呼吸效果,保存忽略临时高亮。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><small><a href="validation.json">visible child under a hidden ancestor cannot be picked or highlighted; trigger aliases include ancestors</a> · unit</small><small><a href="validation.json">highlight rejects missing/hidden targets and transient colors never enter a saved project</a> · unit</small><details><summary>验收要求与证据范围</summary><small>目标正确、找不到报错、结束恢复、保存不永久染色。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p><p><small><b>unit</b>:共用可见性和祖先别名函数;鼠标事件另由 E2E 验证。</small></p><p><small><b>unit</b>:目标不存在/隐藏报错,执行时暂态发光颜色不进入保存文档,结束恢复原材质。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>操作提示节点</strong><code>blueprint.message</code><small><a href="../../../unreal_tran/src/main.js">main.js:2099 · showTeachingMessage</a></small></td><td>现有边界</td><td>显示标题/文本,可点击关闭或约 1.8/2.5 秒自动继续;不是强制人员确认。</td><td>不将其当作业务审核/签名。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>文本出现、关闭和停止不留弹层。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>条件判断节点</strong><code>blueprint.condition</code><small><a href="../../../unreal_tran/src/main.js">main.js:2095 · evaluateBlueprintCondition</a></small></td><td>本轮修复</td><td>当前运行变量、嵌套字段、truthy/布尔/数字比较。</td><td>false 没有出口不走 true,字符串布尔正确解析。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-events.json">已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发</a> · runtime</small><small><a href="validation.json">boolean, numeric and nested blueprint conditions select their true/false branches</a> · unit</small><details><summary>验收要求与证据范围</summary><small>真假分支分别验证,缺出口不误执行。</small><p><small><b>unit</b>:布尔、数字、truthy 与嵌套路径值解析。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>流程完成节点</strong><code>blueprint.finish</code><small><a href="../../../unreal_tran/src/main.js">main.js:1075 · initEditors</a></small></td><td>已有实现</td><td>本次预览结果/进度提示,不写教学任务成绩。</td><td>保持本次运行反馈边界。</td><td><span class="badge pass">已验证</span><small><a href="evidence/truck-blueprint-ui.json">蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</a> · e2e+runtime-read</small><details><summary>验收要求与证据范围</summary><small>成功/完成提示与实际执行结果一致。</small><p><small><b>e2e+runtime-read</b>:节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。</small></p></details></td></tr></tbody></table></div></article><article class="matrix-group" data-group><h3>发布、交付与运行信息</h3><div class="table-scroll"><table class="matrix"><thead><tr><th>功能 / 真实执行路径</th><th>实现状态</th><th>闭环与边界</th><th>本轮对应修复</th><th>测试证据 / 验收要求</th></tr></thead><tbody><tr data-feature-state="PASS"><td><strong>生成 / 发布检查面板</strong><code>publish.preflight</code><small><a href="../../../unreal_tran/src/main.js">main.js:2978 · togglePublishPanel</a></small></td><td>现有边界</td><td>本地主要检查资源引用存在及轨道/节点数量,不执行完整蓝图可达性、终止性或业务校验;服务端发布校验最终生效。</td><td>发布目标与离线交付能力明确。</td><td><span class="badge pass">已验证</span><small><a href="evidence/63-loading-publish-preflight.json">受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>可打开关闭;不完整工程不能凭界面绿标绕过服务端。</small><p><small><b>e2e+api</b>:真实受控下载定向503→中性失败与禁止编辑→解除故障后UI重试成功;预检面板开关不写项目,错误资源JSON在替换当前模型之前被拒绝。服务端发布时code/URI一致性拒绝由ContentProjectServiceTest合同回归覆盖,未把面板绿标代替服务端校验。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>发布到场景资源库</strong><code>publish.api</code><small><a href="../../../unreal_tran/src/main.js">main.js:2897 · publishToSceneLibrary</a></small></td><td>本轮修复</td><td>先保存当前工程再发布固定版本;纯 publisher 发布已保存版本。</td><td>整个保存/发布队列互斥,失败不发后续发布。</td><td><span class="badge pass">已验证</span><small><a href="evidence/34-publish-fixed-version.json">直接发布同步截图封面、固定版本目录与真实离线步骤 HTML</a> · e2e+api</small><small><a href="validation.json">API publish supplies current cover, blocks duplicate publication and reports preserved old cover once</a> · unit</small><small><a href="validation.json">API conflict leaves publication failed and releases the cover guard</a> · unit</small><details><summary>验收要求与证据范围</summary><small>发布版本/模型资产/列表状态一致,保存失败不发布。</small><p><small><b>e2e+api</b>:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。</small></p><p><small><b>unit</b>:实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。</small></p><p><small><b>unit</b>:409 分支不误报已发布并释放 busy 标记;模拟 API。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>发布时当前三维截图封面</strong><code>publish.cover</code><small><a href="../../../unreal_tran/src/main.js">main.js:2897 · publishToSceneLibrary</a></small></td><td>本轮修复</td><td>JPEG 当前视口;截图或上传失败可保留旧封面并明确提示。</td><td>与手动保存共用封面链路,409 阻断。</td><td><span class="badge pass">已验证</span><small><a href="evidence/34-publish-fixed-version.json">直接发布同步截图封面、固定版本目录与真实离线步骤 HTML</a> · e2e+api</small><small><a href="validation.json">API publish supplies current cover, blocks duplicate publication and reports preserved old cover once</a> · unit</small><small><a href="validation.json">API conflict leaves publication failed and releases the cover guard</a> · unit</small><details><summary>验收要求与证据范围</summary><small>真实封面图对应当前模型;上传失败提示一次,旧图保留。</small><p><small><b>e2e+api</b>:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。</small></p><p><small><b>unit</b>:实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。</small></p><p><small><b>unit</b>:409 分支不误报已发布并释放 busy 标记;模拟 API。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>导出步骤演示 HTML</strong><code>publish.html</code><small><a href="../../../unreal_tran/src/main.js">main.js:3011 · exportStandaloneHtml</a></small></td><td>本轮澄清</td><td>工程数据、静态截图和步骤演示;不包含 GLB、不执行真实三维交互。</td><td>生成面板和按钮移除完整离线运行的误导。</td><td><span class="badge pass">已验证</span><small><a href="evidence/34-publish-fixed-version.json">直接发布同步截图封面、固定版本目录与真实离线步骤 HTML</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>下载可打开、步骤导航可用,醒目标明不含三维模型。</small><p><small><b>e2e+api</b>:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>下游读取模型固定版本</strong><code>publish.downstream</code><small><a href="../../../unreal_tran/src/model-content-api.js">model-content-api.js:1159 · publishDocument</a></small></td><td>现有边界</td><td>已发布模型作为资源引用;下游自动执行模型 timeline/blueprint 尚无统一运行桥接。</td><td>本轮不将资源加载成功等同动作自动运行成功。</td><td><span class="badge pass">已验证</span><small><a href="evidence/34-publish-fixed-version.json">直接发布同步截图封面、固定版本目录与真实离线步骤 HTML</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>固定引用/可见性单独测;自动动作执行列为待确认范围。</small><p><small><b>e2e+api</b>:目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>运行日志</strong><code>feedback.log</code><small><a href="../../../unreal_tran/src/main.js">main.js:3116 · log(message</a></small></td><td>已有实现</td><td>本次内存运行日志,最多 160 条;不是服务端审计日志。</td><td>错误信息转义,保留清晰运行结果。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>选中/运行/保存产生相应日志,不要求刷新保留。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>节点 / 三角面 / FPS 等状态</strong><code>feedback.stats</code><small><a href="../../../unreal_tran/src/main.js">main.js:3094 · updateStats</a></small></td><td>现有边界</td><td>节点与三角面统计、当前 FPS;内存为估算值,不是精确浏览器内存剖析。</td><td>无本轮性能仪表重构。</td><td><span class="badge pass">已验证</span><small><a href="evidence/46-navigation-panels-autosave.json">补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</a> · e2e+api</small><details><summary>验收要求与证据范围</summary><small>载入模型后统计有合理变化,状态不作为性能验收数据。</small><p><small><b>e2e+api</b>:真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。</small></p></details></td></tr><tr data-feature-state="PASS"><td><strong>成功 / 错误短消息</strong><code>feedback.toast</code><small><a href="../../../unreal_tran/src/main.js">main.js:3117 · toast(message</a></small></td><td>已有实现</td><td>瞬时反馈;保存/发布成功以接口完成为准。</td><td>封面失败不伪报全部成功。</td><td><span class="badge pass">已验证</span><small><a href="evidence/32-save-failure-recovery.json">保存请求超时和 409 保留恢复副本,解除故障后可重试</a> · e2e+api</small><small><a href="validation.json">API publish supplies current cover, blocks duplicate publication and reports preserved old cover once</a> · unit</small><details><summary>验收要求与证据范围</summary><small>失败出现一次明确提示,自动消失,不形成重复常驻错误条。</small><p><small><b>e2e+api</b>:真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。</small></p><p><small><b>unit</b>:实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。</small></p></details></td></tr></tbody></table></div></article></section>
  12. <section id="testing"><div class="section-label">05 / 测试</div><h2>执行结果与证据分层</h2><article class="panel"><h3>浏览器 E2E</h3><p>19/19 项通过 · <span class="badge pass">已验证</span> · <a href="results.json">Playwright 原始结果</a></p><div class="table-scroll"><table><thead><tr><th>用例</th><th>结果</th><th>耗时 / 失败原因</th></tr></thead><tbody><tr><td>受控模型与外部环境 GLB 上传、JSON 往返和刷新重开</td><td><span class="badge pass">已验证</span></td><td>14.6 秒 </td></tr><tr><td>非法 JSON 与未登记 blob 引用导入失败时保留当前文档</td><td><span class="badge pass">已验证</span></td><td>6.0 秒 </td></tr><tr><td>保存请求超时和 409 保留恢复副本,解除故障后可重试</td><td><span class="badge pass">已验证</span></td><td>9.7 秒 </td></tr><tr><td>直接发布同步截图封面、固定版本目录与真实离线步骤 HTML</td><td><span class="badge pass">已验证</span></td><td>7.9 秒 </td></tr><tr><td>时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致</td><td><span class="badge pass">已验证</span></td><td>11.8 秒 </td></tr><tr><td>补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移</td><td><span class="badge pass">已验证</span></td><td>20.1 秒 </td></tr><tr><td>蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存</td><td><span class="badge pass">已验证</span></td><td>14.1 秒 </td></tr><tr><td>已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发</td><td><span class="badge pass">已验证</span></td><td>13.1 秒 </td></tr><tr><td>对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做</td><td><span class="badge pass">已验证</span></td><td>8.4 秒 </td></tr><tr><td>场景树搜索、可见性、选择、视口工具、原生动画与截图</td><td><span class="badge pass">已验证</span></td><td>15.4 秒 </td></tr><tr><td>新建工程取消及失败保留输入;成功创建新ID且不覆盖当前模型</td><td><span class="badge pass">已验证</span></td><td>10.5 秒 </td></tr><tr><td>管理员只读权限:编辑、新建、导入、保存发布均不可越权</td><td><span class="badge pass">已验证</span></td><td>4.7 秒 </td></tr><tr><td>真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开</td><td><span class="badge pass">已验证</span></td><td>9.4 秒 </td></tr><tr><td>未保存离开:关闭确认保留工作、保存失败留在原页、重试保存后离开</td><td><span class="badge pass">已验证</span></td><td>9.5 秒 </td></tr><tr><td>补充资源库:搜索清空、真实卡片切换与刷新保留</td><td><span class="badge pass">已验证</span></td><td>8.5 秒 </td></tr><tr><td>补充环境与树:内置三环境保存重开、节点计数与折叠展开</td><td><span class="badge pass">已验证</span></td><td>22.8 秒 </td></tr><tr><td>补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存</td><td><span class="badge pass">已验证</span></td><td>34.9 秒 </td></tr><tr><td>真实未保存稿同版本恢复并显式保存;旧版本恢复稿下载隔离保留</td><td><span class="badge pass">已验证</span></td><td>12.5 秒 </td></tr><tr><td>受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON</td><td><span class="badge pass">已验证</span></td><td>9.8 秒 </td></tr></tbody></table></div><p class="muted">通过浏览器定向注入的 409/503 等异常仅验证失败处理,不代表开发服务真实发生该故障。UI 点击、脚本调用运行时和纯 API 检查按各用例证据说明区分。</p></article>
  13. <article class="panel"><h3>保留首轮失败与定向重跑事实</h3><p>仅保留安全的次数、名称、时间及源文件哈希;不复制请求正文、会话、错误上下文或私有运行日志。历史轮次不替代当前 results.json,定向2/2不等同全量19/19。 <a href="run-history.json">安全迭代记录</a></p><div class="table-scroll"><table><thead><tr><th>历史轮次</th><th>原始结果</th><th>解释范围</th></tr></thead><tbody><tr><td>全量首轮</td><td>17/19 通过 · <span class="badge fail">该轮失败</span></td><td>两例均已完成保存并返回列表,末尾测试辅助GET项目详情返回503;分别定位 interaction:114 与 navigation:142。</td></tr><tr><td>首次鉴权诊断定向重跑</td><td>0/2 通过 · <span class="badge fail">该轮失败</span></td><td>此轮才在登录阶段超时,业务操作未开始;不与首轮末尾GET详情503混为同一发生阶段。</td></tr><tr><td>后续定向重跑</td><td>2/2 通过 · <span class="badge pass">该轮通过</span></td><td>只证明这两条在此次运行通过,不能把首轮17/19改写为19/19。</td></tr><tr><td>修复与曲线配色更新后的最终完整轮</td><td>19/19 通过 · <span class="badge pass">该轮通过</span></td><td>保留原始失败,不以随后同名证据覆盖。</td></tr></tbody></table></div><p class="muted">已修复 Auth/Tran 数据库连接健康检查可能无界阻塞的问题,并完成实际 Kingbase 驱动隔离黑洞探针(约2010ms释放关闭);最终双模块构建和完整E2E另行记录。该探针不能证明历史每一次503均已逐条与该原因建立因果关联。</p><p>完成修复后另跑完整19条,使用新的完整results.json、对应时段证据/附件、最终validation及artifact检查;旧失败保留在本历史记录。</p></article>
  14. <article class="panel"><h3>真实 API / 运行时断言</h3><p>逐份读取 evidence/*.json。文件存在本身不代表通过;每份证据须注明断言结果和覆盖的 featureIds。</p><details><summary><a href="evidence/30-assets-roundtrip.json">evidence/30-assets-roundtrip.json</a> <span class="badge pass">已验证</span></summary><pre>{
  15. &quot;time&quot;: &quot;2026-09-06T08:20:27.495Z&quot;,
  16. &quot;data&quot;: {
  17. &quot;status&quot;: &quot;PASS&quot;,
  18. &quot;kind&quot;: &quot;e2e+api&quot;,
  19. &quot;testTitle&quot;: &quot;受控模型与外部环境 GLB 上传、JSON 往返和刷新重开&quot;,
  20. &quot;featureIds&quot;: [
  21. &quot;project.import-glb&quot;,
  22. &quot;environment.external&quot;,
  23. &quot;project.import-json&quot;,
  24. &quot;project.export-json&quot;,
  25. &quot;project.save&quot;
  26. ],
  27. &quot;projectId&quot;: &quot;226&quot;,
  28. &quot;mainCode&quot;: &quot;MODEL_MTPJKFPW_09-FOX&quot;,
  29. &quot;environmentCode&quot;: &quot;ENV_MODEL_MTPJKH7H_01-BOX&quot;,
  30. &quot;mainUri&quot;: &quot;fsvc://unreal-tran/model/2026/09/06/b85bd2722c4e133e61469c9f413380f0.glb&quot;,
  31. &quot;environmentUri&quot;: &quot;fsvc://unreal-tran/model/2026/09/06/9bd7351f3ee917431354690f44a449b5.glb&quot;,
  32. &quot;modelMeshes&quot;: 1,
  33. &quot;environmentMeshes&quot;: 1,
  34. &quot;nativeClips&quot;: 3,
  35. &quot;environmentPosition&quot;: [
  36. 6,
  37. 0,
  38. -7
  39. ],
  40. &quot;environmentScale&quot;: [
  41. 0.15,
  42. 0.15,
  43. 0.15
  44. ],
  45. &quot;result&quot;: &quot;PASS&quot;,
  46. &quot;scope&quot;: &quot;真实上传、注册、保存、JSON重导入、刷新后的实际网格和原生动画目录;未断言下游场景执行动画。&quot;
  47. }
  48. }</pre></details><details><summary><a href="evidence/31-invalid-import.json">evidence/31-invalid-import.json</a> <span class="badge pass">已验证</span></summary><pre>{
  49. &quot;time&quot;: &quot;2026-09-06T08:20:33.535Z&quot;,
  50. &quot;data&quot;: {
  51. &quot;status&quot;: &quot;PASS&quot;,
  52. &quot;kind&quot;: &quot;e2e+api&quot;,
  53. &quot;testTitle&quot;: &quot;非法 JSON 与未登记 blob 引用导入失败时保留当前文档&quot;,
  54. &quot;featureIds&quot;: [
  55. &quot;project.import-json&quot;
  56. ],
  57. &quot;projectId&quot;: &quot;227&quot;,
  58. &quot;result&quot;: &quot;PASS&quot;,
  59. &quot;cases&quot;: [
  60. &quot;JSON语法错误&quot;,
  61. &quot;无受控资源编号/地址的跨页面blob引用&quot;
  62. ],
  63. &quot;retainedVersion&quot;: 1
  64. }
  65. }</pre></details><details><summary><a href="evidence/32-save-failure-recovery.json">evidence/32-save-failure-recovery.json</a> <span class="badge pass">已验证</span></summary><pre>{
  66. &quot;time&quot;: &quot;2026-09-06T08:20:43.214Z&quot;,
  67. &quot;data&quot;: {
  68. &quot;status&quot;: &quot;PASS&quot;,
  69. &quot;kind&quot;: &quot;e2e+api&quot;,
  70. &quot;testTitle&quot;: &quot;保存请求超时和 409 保留恢复副本,解除故障后可重试&quot;,
  71. &quot;featureIds&quot;: [
  72. &quot;project.conflict&quot;,
  73. &quot;project.save&quot;,
  74. &quot;feedback.toast&quot;
  75. ],
  76. &quot;projectId&quot;: &quot;228&quot;,
  77. &quot;result&quot;: &quot;PASS&quot;,
  78. &quot;intercepted&quot;: [
  79. {
  80. &quot;mode&quot;: &quot;timedout&quot;,
  81. &quot;method&quot;: &quot;PUT&quot;,
  82. &quot;projectId&quot;: &quot;228&quot;
  83. },
  84. {
  85. &quot;mode&quot;: &quot;409&quot;,
  86. &quot;method&quot;: &quot;PUT&quot;,
  87. &quot;projectId&quot;: &quot;228&quot;
  88. }
  89. ],
  90. &quot;scope&quot;: &quot;真实页面保存及真实服务端重试;失败由浏览器定向注入 timedout/409,非宣称自然发生的服务故障。&quot;
  91. }
  92. }</pre></details><details><summary><a href="evidence/34-publish-fixed-version.json">evidence/34-publish-fixed-version.json</a> <span class="badge pass">已验证</span></summary><pre>{
  93. &quot;time&quot;: &quot;2026-09-06T08:20:51.047Z&quot;,
  94. &quot;data&quot;: {
  95. &quot;status&quot;: &quot;PASS&quot;,
  96. &quot;kind&quot;: &quot;e2e+api&quot;,
  97. &quot;testTitle&quot;: &quot;直接发布同步截图封面、固定版本目录与真实离线步骤 HTML&quot;,
  98. &quot;featureIds&quot;: [
  99. &quot;publish.api&quot;,
  100. &quot;publish.cover&quot;,
  101. &quot;publish.html&quot;,
  102. &quot;publish.downstream&quot;
  103. ],
  104. &quot;projectId&quot;: &quot;229&quot;,
  105. &quot;result&quot;: &quot;PASS&quot;,
  106. &quot;versionId&quot;: &quot;283&quot;,
  107. &quot;coverUri&quot;: &quot;fsvc://unreal-tran/image/2026/09/06/14ab7b4e1e7a9d21f13f3504cb8b89ae.jpg&quot;,
  108. &quot;priorCoverUri&quot;: &quot;fsvc://unreal-tran/image/2026/09/05/c09a49efd4423dcf8ccbc46b46d1e209.jpg&quot;,
  109. &quot;mainCode&quot;: &quot;MODEL_MTO6V5W6_09-FOX&quot;,
  110. &quot;scope&quot;: &quot;目录可取得固定发布版本及同版封面;HTML已真实打开并确认演示边界,未声明下游动画执行或完整离线三维运行。&quot;
  111. }
  112. }</pre></details><details><summary><a href="evidence/41-resource-search-switch.json">evidence/41-resource-search-switch.json</a> <span class="badge pass">已验证</span></summary><pre>{
  113. &quot;time&quot;: &quot;2026-09-06T08:22:56.960Z&quot;,
  114. &quot;data&quot;: {
  115. &quot;status&quot;: &quot;PASS&quot;,
  116. &quot;kind&quot;: &quot;e2e+api&quot;,
  117. &quot;testTitle&quot;: &quot;补充资源库:搜索清空、真实卡片切换与刷新保留&quot;,
  118. &quot;featureIds&quot;: [
  119. &quot;resource.search&quot;,
  120. &quot;resource.catalog&quot;
  121. ],
  122. &quot;projectId&quot;: &quot;235&quot;,
  123. &quot;original&quot;: {
  124. &quot;id&quot;: &quot;imported-model_mto6v5w6_09-fox&quot;,
  125. &quot;name&quot;: &quot;09-Fox&quot;,
  126. &quot;code&quot;: &quot;MODEL_MTO6V5W6_09-FOX&quot;
  127. },
  128. &quot;boxId&quot;: &quot;imported-model_mtpjnqqk_01-box&quot;,
  129. &quot;restored&quot;: {
  130. &quot;id&quot;: &quot;imported-model_mto6v5w6_09-fox&quot;,
  131. &quot;code&quot;: &quot;MODEL_MTO6V5W6_09-FOX&quot;,
  132. &quot;meshes&quot;: 1
  133. },
  134. &quot;scope&quot;: &quot;真实搜索与资源卡片点击、服务端保存、刷新后原模型网格;副本独立登记待清理。&quot;
  135. }
  136. }</pre></details><details><summary><a href="evidence/43-builtin-environments-tree.json">evidence/43-builtin-environments-tree.json</a> <span class="badge pass">已验证</span></summary><pre>{
  137. &quot;time&quot;: &quot;2026-09-06T08:23:19.759Z&quot;,
  138. &quot;data&quot;: {
  139. &quot;status&quot;: &quot;PASS&quot;,
  140. &quot;kind&quot;: &quot;e2e+api&quot;,
  141. &quot;testTitle&quot;: &quot;补充环境与树:内置三环境保存重开、节点计数与折叠展开&quot;,
  142. &quot;featureIds&quot;: [
  143. &quot;environment.builtin&quot;,
  144. &quot;tree.browse&quot;,
  145. &quot;tree.expand&quot;,
  146. &quot;project.leave&quot;
  147. ],
  148. &quot;projectId&quot;: &quot;236&quot;,
  149. &quot;snapshots&quot;: [
  150. {
  151. &quot;type&quot;: &quot;workshop&quot;,
  152. &quot;mode&quot;: &quot;placeholder&quot;,
  153. &quot;sourceKind&quot;: &quot;placeholder&quot;,
  154. &quot;nodes&quot;: 48,
  155. &quot;meshes&quot;: 45,
  156. &quot;id&quot;: &quot;ee302132-152c-4575-a2ec-0a56b4820079&quot;,
  157. &quot;shownRows&quot;: 76,
  158. &quot;totalNodes&quot;: 76
  159. },
  160. {
  161. &quot;type&quot;: &quot;outdoor&quot;,
  162. &quot;mode&quot;: &quot;placeholder&quot;,
  163. &quot;sourceKind&quot;: &quot;placeholder&quot;,
  164. &quot;nodes&quot;: 70,
  165. &quot;meshes&quot;: 65,
  166. &quot;id&quot;: &quot;bf88db35-635d-4012-8df6-dd41382e624f&quot;,
  167. &quot;shownRows&quot;: 98,
  168. &quot;totalNodes&quot;: 98
  169. },
  170. {
  171. &quot;type&quot;: &quot;depot&quot;,
  172. &quot;mode&quot;: &quot;placeholder&quot;,
  173. &quot;sourceKind&quot;: &quot;builtin-gltf&quot;,
  174. &quot;nodes&quot;: 41,
  175. &quot;meshes&quot;: 32,
  176. &quot;id&quot;: &quot;cebab0bb-6910-4dff-b846-9978adcb3450&quot;,
  177. &quot;shownRows&quot;: 69,
  178. &quot;totalNodes&quot;: 69
  179. }
  180. ],
  181. &quot;depotSavedLeave&quot;: {
  182. &quot;promptedForUnsavedChanges&quot;: false,
  183. &quot;version&quot;: 5
  184. },
  185. &quot;scope&quot;: &quot;真实切换、保存和刷新三种环境;树计数与展开折叠;装备车库保存后返回列表不误报未保存。树220行上限仍属已说明边界。&quot;
  186. }
  187. }</pre></details><details><summary><a href="evidence/46-navigation-panels-autosave.json">evidence/46-navigation-panels-autosave.json</a> <span class="badge pass">已验证</span></summary><pre>{
  188. &quot;time&quot;: &quot;2026-09-06T08:23:54.656Z&quot;,
  189. &quot;data&quot;: {
  190. &quot;status&quot;: &quot;PASS&quot;,
  191. &quot;kind&quot;: &quot;e2e+api&quot;,
  192. &quot;testTitle&quot;: &quot;补充视口与工作区:鼠标镜头、聚焦、面板、预览导航、日志与自动保存&quot;,
  193. &quot;featureIds&quot;: [
  194. &quot;project.name&quot;,
  195. &quot;project.autosave&quot;,
  196. &quot;view.orbit&quot;,
  197. &quot;view.focus&quot;,
  198. &quot;view.panels&quot;,
  199. &quot;view.preview-step&quot;,
  200. &quot;feedback.log&quot;,
  201. &quot;feedback.stats&quot;,
  202. &quot;property.identity&quot;,
  203. &quot;property.binding&quot;,
  204. &quot;selection.scope&quot;,
  205. &quot;component.inspect&quot;
  206. ],
  207. &quot;projectId&quot;: &quot;237&quot;,
  208. &quot;focused&quot;: {
  209. &quot;position&quot;: [
  210. 11.153569378931522,
  211. 8.526809324389628,
  212. 13.922975975299929
  213. ],
  214. &quot;target&quot;: [
  215. 0.01518877997232826,
  216. 2.4006999949620704,
  217. 2.266009371254541e-7
  218. ],
  219. &quot;distance&quot;: 18.853169271563605
  220. },
  221. &quot;rotated&quot;: {
  222. &quot;position&quot;: [
  223. 1.7511663652214757,
  224. 6.181727848275404,
  225. 18.38837160033089
  226. ],
  227. &quot;target&quot;: [
  228. 0.01518877997232826,
  229. 2.4006999949620704,
  230. 2.266009371254541e-7
  231. ],
  232. &quot;distance&quot;: 18.853169271563594
  233. },
  234. &quot;panned&quot;: {
  235. &quot;position&quot;: [
  236. -5.273341581654527,
  237. 5.082450786888863,
  238. 17.990688935160133
  239. ],
  240. &quot;target&quot;: [
  241. -0.5866856170824521,
  242. 2.73698783970429,
  243. -0.11942014831462
  244. ],
  245. &quot;distance&quot;: 18.85316927156359
  246. },
  247. &quot;focusTargetScreen&quot;: [
  248. -5.177525136316571e-19,
  249. -1.227265217497261e-16,
  250. 0.9980999049952497
  251. ],
  252. &quot;panelModes&quot;: [
  253. &quot;timeline&quot;,
  254. &quot;blueprint&quot;,
  255. &quot;curve&quot;,
  256. &quot;console&quot;
  257. ],
  258. &quot;logCount&quot;: 8,
  259. &quot;stats&quot;: {
  260. &quot;objects&quot;: &quot;98 节点 / 66 网格&quot;,
  261. &quot;triangles&quot;: &quot;1,438&quot;,
  262. &quot;fps&quot;: &quot;54&quot;
  263. },
  264. &quot;scope&quot;: &quot;真实鼠标镜头操作;聚焦只验证相机目标;真实30秒自动保存,无测试加速定时器;统计内存估值未当作性能结论。&quot;
  265. }
  266. }</pre></details><details><summary><a href="evidence/51-gizmos.json">evidence/51-gizmos.json</a> <span class="badge pass">已验证</span></summary><pre>{
  267. &quot;time&quot;: &quot;2026-09-06T08:22:38.815Z&quot;,
  268. &quot;data&quot;: {
  269. &quot;status&quot;: &quot;PASS&quot;,
  270. &quot;kind&quot;: &quot;e2e+runtime-readback&quot;,
  271. &quot;testTitle&quot;: &quot;真实三维移动、旋转、缩放手柄拖动及撤销重做保存重开&quot;,
  272. &quot;featureIds&quot;: [
  273. &quot;view.move&quot;,
  274. &quot;view.rotate&quot;,
  275. &quot;view.scale&quot;
  276. ],
  277. &quot;projectId&quot;: &quot;233&quot;,
  278. &quot;changes&quot;: [
  279. {
  280. &quot;mode&quot;: &quot;translate&quot;,
  281. &quot;before&quot;: [
  282. 0,
  283. 0,
  284. 0
  285. ],
  286. &quot;after&quot;: [
  287. 0.7257266613731312,
  288. 0,
  289. 0
  290. ]
  291. },
  292. {
  293. &quot;mode&quot;: &quot;rotate&quot;,
  294. &quot;before&quot;: [
  295. 0,
  296. 0,
  297. 0
  298. ],
  299. &quot;after&quot;: [
  300. -1.194547194225429,
  301. 0,
  302. 0
  303. ]
  304. },
  305. {
  306. &quot;mode&quot;: &quot;scale&quot;,
  307. &quot;before&quot;: [
  308. 1,
  309. 1,
  310. 1
  311. ],
  312. &quot;after&quot;: [
  313. 0.30167729043770014,
  314. 1,
  315. 1
  316. ]
  317. }
  318. ],
  319. &quot;reopened&quot;: {
  320. &quot;position&quot;: [
  321. 0.7257266613731312,
  322. 0,
  323. 0
  324. ],
  325. &quot;rotation&quot;: [
  326. -1.194547194225429,
  327. 0,
  328. 0
  329. ],
  330. &quot;scale&quot;: [
  331. 0.30167729043770014,
  332. 1,
  333. 1
  334. ]
  335. }
  336. }
  337. }</pre></details><details><summary><a href="evidence/52-leave.json">evidence/52-leave.json</a> <span class="badge pass">已验证</span></summary><pre>{
  338. &quot;time&quot;: &quot;2026-09-06T08:22:48.155Z&quot;,
  339. &quot;data&quot;: {
  340. &quot;status&quot;: &quot;PASS&quot;,
  341. &quot;kind&quot;: &quot;e2e+api&quot;,
  342. &quot;testTitle&quot;: &quot;未保存离开:关闭确认保留工作、保存失败留在原页、重试保存后离开&quot;,
  343. &quot;featureIds&quot;: [
  344. &quot;project.leave&quot;
  345. ],
  346. &quot;projectId&quot;: &quot;234&quot;,
  347. &quot;closeKeptDraft&quot;: true,
  348. &quot;failureKeptDraft&quot;: true,
  349. &quot;retriedSavePersisted&quot;: true
  350. }
  351. }</pre></details><details><summary><a href="evidence/60-project-recovery.json">evidence/60-project-recovery.json</a> <span class="badge pass">已验证</span></summary><pre>{
  352. &quot;time&quot;: &quot;2026-09-06T08:24:07.184Z&quot;,
  353. &quot;data&quot;: {
  354. &quot;status&quot;: &quot;PASS&quot;,
  355. &quot;kind&quot;: &quot;e2e+api&quot;,
  356. &quot;testTitle&quot;: &quot;真实未保存稿同版本恢复并显式保存;旧版本恢复稿下载隔离保留&quot;,
  357. &quot;featureIds&quot;: [
  358. &quot;project.recovery&quot;
  359. ],
  360. &quot;projectId&quot;: &quot;238&quot;,
  361. &quot;sameVersion&quot;: 1,
  362. &quot;explicitSaveVersion&quot;: 2,
  363. &quot;concurrentVersion&quot;: 3,
  364. &quot;retainedFilename&quot;: &quot;recovery-238-isolated.json&quot;,
  365. &quot;scope&quot;: &quot;通过真实beforeunload创建未保存稿;同版恢复后仅显式保存落库;旧版只下载隔离,不自动覆盖服务端。丢弃/跨标签竞态另由既有恢复合同测试覆盖。&quot;
  366. }
  367. }</pre></details><details><summary><a href="evidence/63-loading-publish-preflight.json">evidence/63-loading-publish-preflight.json</a> <span class="badge pass">已验证</span></summary><pre>{
  368. &quot;time&quot;: &quot;2026-09-06T08:24:17.025Z&quot;,
  369. &quot;data&quot;: {
  370. &quot;status&quot;: &quot;PASS&quot;,
  371. &quot;kind&quot;: &quot;e2e+api&quot;,
  372. &quot;testTitle&quot;: &quot;受控 GLB 下载失败阻止编辑,重试成功;发布预检开关无写入且拒绝错误资源 JSON&quot;,
  373. &quot;featureIds&quot;: [
  374. &quot;resource.loading&quot;,
  375. &quot;publish.preflight&quot;
  376. ],
  377. &quot;projectId&quot;: &quot;239&quot;,
  378. &quot;failedDownloads&quot;: 1,
  379. &quot;retainedVersion&quot;: 1,
  380. &quot;scope&quot;: &quot;真实受控下载定向503→中性失败与禁止编辑→解除故障后UI重试成功;预检面板开关不写项目,错误资源JSON在替换当前模型之前被拒绝。服务端发布时code/URI一致性拒绝由ContentProjectServiceTest合同回归覆盖,未把面板绿标代替服务端校验。&quot;
  381. }
  382. }</pre></details><details><summary><a href="evidence/new-project.json">evidence/new-project.json</a> <span class="badge pass">已验证</span></summary><pre>{
  383. &quot;time&quot;: &quot;2026-09-06T08:22:24.723Z&quot;,
  384. &quot;data&quot;: {
  385. &quot;status&quot;: &quot;PASS&quot;,
  386. &quot;kind&quot;: &quot;e2e+api&quot;,
  387. &quot;testTitle&quot;: &quot;新建工程取消及失败保留输入;成功创建新ID且不覆盖当前模型&quot;,
  388. &quot;featureIds&quot;: [
  389. &quot;project.new&quot;
  390. ],
  391. &quot;oldId&quot;: &quot;168&quot;,
  392. &quot;newId&quot;: &quot;232&quot;,
  393. &quot;cancelPreserved&quot;: true,
  394. &quot;failureRetainedName&quot;: true,
  395. &quot;originalVersion&quot;: 17,
  396. &quot;sourceUnchanged&quot;: true
  397. }
  398. }</pre></details><details><summary><a href="evidence/permissions.json">evidence/permissions.json</a> <span class="badge pass">已验证</span></summary><pre>{
  399. &quot;time&quot;: &quot;2026-09-06T08:22:29.489Z&quot;,
  400. &quot;data&quot;: {
  401. &quot;status&quot;: &quot;PASS&quot;,
  402. &quot;kind&quot;: &quot;e2e+api&quot;,
  403. &quot;testTitle&quot;: &quot;管理员只读权限:编辑、新建、导入、保存发布均不可越权&quot;,
  404. &quot;featureIds&quot;: [
  405. &quot;project.permissions&quot;
  406. ],
  407. &quot;scope&quot;: &quot;管理员只读UI、真实键盘搜索、原生片段切换与Enter播放/暂停、预览无内容写请求及创建403;纯publisher无需update的发布流程由独立权限合同回归补充。&quot;,
  408. &quot;readonlyUi&quot;: true,
  409. &quot;readonlySearch&quot;: true,
  410. &quot;nativeClipChanged&quot;: true,
  411. &quot;keyboardPreview&quot;: true,
  412. &quot;previewWriteRequests&quot;: 0,
  413. &quot;createStatus&quot;: 403
  414. }
  415. }</pre></details><details><summary><a href="evidence/properties.json">evidence/properties.json</a> <span class="badge pass">已验证</span></summary><pre>{
  416. &quot;time&quot;: &quot;2026-09-06T08:21:58.738Z&quot;,
  417. &quot;data&quot;: {
  418. &quot;status&quot;: &quot;PASS&quot;,
  419. &quot;kind&quot;: &quot;e2e+api&quot;,
  420. &quot;testTitle&quot;: &quot;对象名称、变换、PBR、属性与扩展标记保存重开;撤销重做&quot;,
  421. &quot;featureIds&quot;: [
  422. &quot;property.name&quot;,
  423. &quot;property.position&quot;,
  424. &quot;property.rotation&quot;,
  425. &quot;property.scale&quot;,
  426. &quot;property.color&quot;,
  427. &quot;property.metalness&quot;,
  428. &quot;property.roughness&quot;,
  429. &quot;property.opacity&quot;,
  430. &quot;property.code&quot;,
  431. &quot;property.status&quot;,
  432. &quot;component.tag&quot;,
  433. &quot;project.undo&quot;,
  434. &quot;project.redo&quot;,
  435. &quot;project.save&quot;
  436. ],
  437. &quot;scope&quot;: &quot;真实属性输入/材质参数/标签、保存与刷新;变换只验数值输入,不代替三维 gizmo 拖动。&quot;,
  438. &quot;state&quot;: {
  439. &quot;id&quot;: &quot;model-imported-model_mto6v5w6_09-fox-26&quot;,
  440. &quot;position&quot;: [
  441. 1.25,
  442. 0,
  443. 0
  444. ],
  445. &quot;rotation&quot;: [
  446. 0,
  447. 0.2617993877991494,
  448. 0
  449. ],
  450. &quot;scale&quot;: [
  451. 1,
  452. 1,
  453. 1.1
  454. ],
  455. &quot;customProperties&quot;: {
  456. &quot;resourceCode&quot;: &quot;CLOSURE-FOX-001&quot;,
  457. &quot;operatingStatus&quot;: &quot;SERVICE&quot;
  458. },
  459. &quot;customComponents&quot;: [
  460. &quot;扩展标记 1&quot;,
  461. &quot;扩展标记 2&quot;,
  462. &quot;扩展标记 3&quot;,
  463. &quot;扩展标记 4&quot;,
  464. &quot;扩展标记 5&quot;
  465. ]
  466. },
  467. &quot;serverVersion&quot;: 15,
  468. &quot;persisted&quot;: true
  469. }
  470. }</pre></details><details><summary><a href="evidence/truck-blueprint-events.json">evidence/truck-blueprint-events.json</a> <span class="badge pass">已验证</span></summary><pre>{
  471. &quot;time&quot;: &quot;2026-09-06T08:21:50.227Z&quot;,
  472. &quot;data&quot;: {
  473. &quot;status&quot;: &quot;PASS&quot;,
  474. &quot;kind&quot;: &quot;e2e&quot;,
  475. &quot;testTitle&quot;: &quot;已保存蓝图:条件出口与目标匹配 runtime 检查,真实模型单击/双击/进入预览自动触发&quot;,
  476. &quot;featureIds&quot;: [
  477. &quot;blueprint.click&quot;,
  478. &quot;blueprint.double-click&quot;,
  479. &quot;blueprint.auto&quot;,
  480. &quot;view.preview&quot;
  481. ],
  482. &quot;projectId&quot;: &quot;169&quot;,
  483. &quot;runtimeSupplement&quot;: {
  484. &quot;status&quot;: &quot;PASS&quot;,
  485. &quot;kind&quot;: &quot;runtime&quot;,
  486. &quot;featureIds&quot;: [
  487. &quot;blueprint.condition&quot;
  488. ],
  489. &quot;branches&quot;: {
  490. &quot;falseBranch&quot;: {
  491. &quot;result&quot;: true,
  492. &quot;visitedFinish&quot;: false,
  493. &quot;logs&quot;: [
  494. {
  495. &quot;time&quot;: &quot;16:21:41&quot;,
  496. &quot;message&quot;: &quot;开始执行 · 闭环-条件判断&quot;,
  497. &quot;level&quot;: &quot;run&quot;,
  498. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  499. },
  500. {
  501. &quot;time&quot;: &quot;16:21:41&quot;,
  502. &quot;message&quot;: &quot;执行节点:闭环-条件判断&quot;,
  503. &quot;level&quot;: &quot;run&quot;,
  504. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  505. },
  506. {
  507. &quot;time&quot;: &quot;16:21:41&quot;,
  508. &quot;message&quot;: &quot;条件结果:否 / FALSE&quot;,
  509. &quot;level&quot;: &quot;warning&quot;,
  510. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  511. },
  512. {
  513. &quot;time&quot;: &quot;16:21:41&quot;,
  514. &quot;message&quot;: &quot;节点“闭环-条件判断”没有后续连线,流程结束&quot;,
  515. &quot;level&quot;: &quot;warning&quot;,
  516. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  517. },
  518. {
  519. &quot;time&quot;: &quot;16:21:41&quot;,
  520. &quot;message&quot;: &quot;蓝图执行完成 · 1 个节点&quot;,
  521. &quot;level&quot;: &quot;success&quot;,
  522. &quot;nodeId&quot;: null
  523. }
  524. ]
  525. },
  526. &quot;trueBranch&quot;: {
  527. &quot;result&quot;: true,
  528. &quot;visitedFinish&quot;: true,
  529. &quot;logs&quot;: [
  530. {
  531. &quot;time&quot;: &quot;16:21:41&quot;,
  532. &quot;message&quot;: &quot;开始执行 · 闭环-条件判断&quot;,
  533. &quot;level&quot;: &quot;run&quot;,
  534. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  535. },
  536. {
  537. &quot;time&quot;: &quot;16:21:41&quot;,
  538. &quot;message&quot;: &quot;执行节点:闭环-条件判断&quot;,
  539. &quot;level&quot;: &quot;run&quot;,
  540. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  541. },
  542. {
  543. &quot;time&quot;: &quot;16:21:41&quot;,
  544. &quot;message&quot;: &quot;条件结果:是 / TRUE&quot;,
  545. &quot;level&quot;: &quot;success&quot;,
  546. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  547. },
  548. {
  549. &quot;time&quot;: &quot;16:21:41&quot;,
  550. &quot;message&quot;: &quot;执行节点:闭环-流程完成&quot;,
  551. &quot;level&quot;: &quot;run&quot;,
  552. &quot;nodeId&quot;: &quot;node-mtpjlznf-cxlzk&quot;
  553. },
  554. {
  555. &quot;time&quot;: &quot;16:21:41&quot;,
  556. &quot;message&quot;: &quot;蓝图执行完成 · 2 个节点&quot;,
  557. &quot;level&quot;: &quot;success&quot;,
  558. &quot;nodeId&quot;: null
  559. }
  560. ]
  561. }
  562. },
  563. &quot;mismatch&quot;: {
  564. &quot;result&quot;: false,
  565. &quot;started&quot;: false
  566. }
  567. },
  568. &quot;browserEvents&quot;: [
  569. {
  570. &quot;event&quot;: &quot;click&quot;,
  571. &quot;starts&quot;: 1,
  572. &quot;finished&quot;: true,
  573. &quot;source&quot;: &quot;真实 renderer canvas 指针事件&quot;,
  574. &quot;logs&quot;: [
  575. {
  576. &quot;time&quot;: &quot;16:21:42&quot;,
  577. &quot;message&quot;: &quot;运行状态已重置&quot;,
  578. &quot;level&quot;: &quot;system&quot;,
  579. &quot;nodeId&quot;: null
  580. },
  581. {
  582. &quot;time&quot;: &quot;16:21:42&quot;,
  583. &quot;message&quot;: &quot;开始执行 · 闭环-点击触发&quot;,
  584. &quot;level&quot;: &quot;run&quot;,
  585. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  586. },
  587. {
  588. &quot;time&quot;: &quot;16:21:42&quot;,
  589. &quot;message&quot;: &quot;执行节点:闭环-点击触发&quot;,
  590. &quot;level&quot;: &quot;run&quot;,
  591. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  592. },
  593. {
  594. &quot;time&quot;: &quot;16:21:42&quot;,
  595. &quot;message&quot;: &quot;执行节点:闭环-播放时间轴&quot;,
  596. &quot;level&quot;: &quot;run&quot;,
  597. &quot;nodeId&quot;: &quot;node-mtpjlxj9-y3g3v&quot;
  598. },
  599. {
  600. &quot;time&quot;: &quot;16:21:42&quot;,
  601. &quot;message&quot;: &quot;执行节点:闭环-等待&quot;,
  602. &quot;level&quot;: &quot;run&quot;,
  603. &quot;nodeId&quot;: &quot;node-mtpjlxxe-ond97&quot;
  604. },
  605. {
  606. &quot;time&quot;: &quot;16:21:42&quot;,
  607. &quot;message&quot;: &quot;执行节点:闭环-高亮部件&quot;,
  608. &quot;level&quot;: &quot;run&quot;,
  609. &quot;nodeId&quot;: &quot;node-mtpjlyci-4c5oi&quot;
  610. },
  611. {
  612. &quot;time&quot;: &quot;16:21:42&quot;,
  613. &quot;message&quot;: &quot;执行节点:闭环-操作提示&quot;,
  614. &quot;level&quot;: &quot;run&quot;,
  615. &quot;nodeId&quot;: &quot;node-mtpjlyuw-164xj&quot;
  616. },
  617. {
  618. &quot;time&quot;: &quot;16:21:43&quot;,
  619. &quot;message&quot;: &quot;执行节点:闭环-条件判断&quot;,
  620. &quot;level&quot;: &quot;run&quot;,
  621. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  622. },
  623. {
  624. &quot;time&quot;: &quot;16:21:43&quot;,
  625. &quot;message&quot;: &quot;条件结果:是 / TRUE&quot;,
  626. &quot;level&quot;: &quot;success&quot;,
  627. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  628. },
  629. {
  630. &quot;time&quot;: &quot;16:21:43&quot;,
  631. &quot;message&quot;: &quot;执行节点:闭环-流程完成&quot;,
  632. &quot;level&quot;: &quot;run&quot;,
  633. &quot;nodeId&quot;: &quot;node-mtpjlznf-cxlzk&quot;
  634. },
  635. {
  636. &quot;time&quot;: &quot;16:21:43&quot;,
  637. &quot;message&quot;: &quot;蓝图执行完成 · 7 个节点&quot;,
  638. &quot;level&quot;: &quot;success&quot;,
  639. &quot;nodeId&quot;: null
  640. }
  641. ]
  642. },
  643. {
  644. &quot;event&quot;: &quot;double-click&quot;,
  645. &quot;starts&quot;: 1,
  646. &quot;finished&quot;: true,
  647. &quot;source&quot;: &quot;真实 renderer canvas 指针事件&quot;,
  648. &quot;logs&quot;: [
  649. {
  650. &quot;time&quot;: &quot;16:21:43&quot;,
  651. &quot;message&quot;: &quot;运行状态已重置&quot;,
  652. &quot;level&quot;: &quot;system&quot;,
  653. &quot;nodeId&quot;: null
  654. },
  655. {
  656. &quot;time&quot;: &quot;16:21:44&quot;,
  657. &quot;message&quot;: &quot;开始执行 · 闭环-点击触发&quot;,
  658. &quot;level&quot;: &quot;run&quot;,
  659. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  660. },
  661. {
  662. &quot;time&quot;: &quot;16:21:44&quot;,
  663. &quot;message&quot;: &quot;执行节点:闭环-点击触发&quot;,
  664. &quot;level&quot;: &quot;run&quot;,
  665. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  666. },
  667. {
  668. &quot;time&quot;: &quot;16:21:44&quot;,
  669. &quot;message&quot;: &quot;执行节点:闭环-播放时间轴&quot;,
  670. &quot;level&quot;: &quot;run&quot;,
  671. &quot;nodeId&quot;: &quot;node-mtpjlxj9-y3g3v&quot;
  672. },
  673. {
  674. &quot;time&quot;: &quot;16:21:44&quot;,
  675. &quot;message&quot;: &quot;执行节点:闭环-等待&quot;,
  676. &quot;level&quot;: &quot;run&quot;,
  677. &quot;nodeId&quot;: &quot;node-mtpjlxxe-ond97&quot;
  678. },
  679. {
  680. &quot;time&quot;: &quot;16:21:44&quot;,
  681. &quot;message&quot;: &quot;执行节点:闭环-高亮部件&quot;,
  682. &quot;level&quot;: &quot;run&quot;,
  683. &quot;nodeId&quot;: &quot;node-mtpjlyci-4c5oi&quot;
  684. },
  685. {
  686. &quot;time&quot;: &quot;16:21:44&quot;,
  687. &quot;message&quot;: &quot;执行节点:闭环-操作提示&quot;,
  688. &quot;level&quot;: &quot;run&quot;,
  689. &quot;nodeId&quot;: &quot;node-mtpjlyuw-164xj&quot;
  690. },
  691. {
  692. &quot;time&quot;: &quot;16:21:45&quot;,
  693. &quot;message&quot;: &quot;执行节点:闭环-条件判断&quot;,
  694. &quot;level&quot;: &quot;run&quot;,
  695. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  696. },
  697. {
  698. &quot;time&quot;: &quot;16:21:45&quot;,
  699. &quot;message&quot;: &quot;条件结果:是 / TRUE&quot;,
  700. &quot;level&quot;: &quot;success&quot;,
  701. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  702. },
  703. {
  704. &quot;time&quot;: &quot;16:21:45&quot;,
  705. &quot;message&quot;: &quot;执行节点:闭环-流程完成&quot;,
  706. &quot;level&quot;: &quot;run&quot;,
  707. &quot;nodeId&quot;: &quot;node-mtpjlznf-cxlzk&quot;
  708. },
  709. {
  710. &quot;time&quot;: &quot;16:21:45&quot;,
  711. &quot;message&quot;: &quot;蓝图执行完成 · 7 个节点&quot;,
  712. &quot;level&quot;: &quot;success&quot;,
  713. &quot;nodeId&quot;: null
  714. }
  715. ]
  716. },
  717. {
  718. &quot;event&quot;: &quot;auto&quot;,
  719. &quot;starts&quot;: 1,
  720. &quot;finished&quot;: true,
  721. &quot;source&quot;: &quot;真实点击进入预览&quot;,
  722. &quot;logs&quot;: [
  723. {
  724. &quot;time&quot;: &quot;16:21:45&quot;,
  725. &quot;message&quot;: &quot;运行状态已重置&quot;,
  726. &quot;level&quot;: &quot;system&quot;,
  727. &quot;nodeId&quot;: null
  728. },
  729. {
  730. &quot;time&quot;: &quot;16:21:45&quot;,
  731. &quot;message&quot;: &quot;开始执行 · 闭环-点击触发&quot;,
  732. &quot;level&quot;: &quot;run&quot;,
  733. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  734. },
  735. {
  736. &quot;time&quot;: &quot;16:21:45&quot;,
  737. &quot;message&quot;: &quot;执行节点:闭环-点击触发&quot;,
  738. &quot;level&quot;: &quot;run&quot;,
  739. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  740. },
  741. {
  742. &quot;time&quot;: &quot;16:21:45&quot;,
  743. &quot;message&quot;: &quot;执行节点:闭环-播放时间轴&quot;,
  744. &quot;level&quot;: &quot;run&quot;,
  745. &quot;nodeId&quot;: &quot;node-mtpjlxj9-y3g3v&quot;
  746. },
  747. {
  748. &quot;time&quot;: &quot;16:21:45&quot;,
  749. &quot;message&quot;: &quot;执行节点:闭环-等待&quot;,
  750. &quot;level&quot;: &quot;run&quot;,
  751. &quot;nodeId&quot;: &quot;node-mtpjlxxe-ond97&quot;
  752. },
  753. {
  754. &quot;time&quot;: &quot;16:21:45&quot;,
  755. &quot;message&quot;: &quot;执行节点:闭环-高亮部件&quot;,
  756. &quot;level&quot;: &quot;run&quot;,
  757. &quot;nodeId&quot;: &quot;node-mtpjlyci-4c5oi&quot;
  758. },
  759. {
  760. &quot;time&quot;: &quot;16:21:46&quot;,
  761. &quot;message&quot;: &quot;执行节点:闭环-操作提示&quot;,
  762. &quot;level&quot;: &quot;run&quot;,
  763. &quot;nodeId&quot;: &quot;node-mtpjlyuw-164xj&quot;
  764. },
  765. {
  766. &quot;time&quot;: &quot;16:21:46&quot;,
  767. &quot;message&quot;: &quot;执行节点:闭环-条件判断&quot;,
  768. &quot;level&quot;: &quot;run&quot;,
  769. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  770. },
  771. {
  772. &quot;time&quot;: &quot;16:21:46&quot;,
  773. &quot;message&quot;: &quot;条件结果:是 / TRUE&quot;,
  774. &quot;level&quot;: &quot;success&quot;,
  775. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  776. },
  777. {
  778. &quot;time&quot;: &quot;16:21:46&quot;,
  779. &quot;message&quot;: &quot;执行节点:闭环-流程完成&quot;,
  780. &quot;level&quot;: &quot;run&quot;,
  781. &quot;nodeId&quot;: &quot;node-mtpjlznf-cxlzk&quot;
  782. },
  783. {
  784. &quot;time&quot;: &quot;16:21:46&quot;,
  785. &quot;message&quot;: &quot;蓝图执行完成 · 7 个节点&quot;,
  786. &quot;level&quot;: &quot;success&quot;,
  787. &quot;nodeId&quot;: null
  788. }
  789. ]
  790. }
  791. ],
  792. &quot;persistedNodeCount&quot;: 7,
  793. &quot;persistedEdgeCount&quot;: 6,
  794. &quot;scope&quot;: &quot;执行使用正式模型编辑器的真实模型/时间轴/高亮/提示 handler;不等同于学员端任务下发。&quot;
  795. }
  796. }</pre></details><details><summary><a href="evidence/truck-blueprint-tool-supplement.json">evidence/truck-blueprint-tool-supplement.json</a> <span class="badge pass">已验证</span></summary><pre>{
  797. &quot;time&quot;: &quot;2026-09-06T08:21:23.003Z&quot;,
  798. &quot;data&quot;: {
  799. &quot;status&quot;: &quot;PASS&quot;,
  800. &quot;kind&quot;: &quot;e2e+runtime-read&quot;,
  801. &quot;testTitle&quot;: &quot;补充时间轴与蓝图工具:刻度/按键/记录/分量、基准匹配、节点搜索拖入与画布平移&quot;,
  802. &quot;featureIds&quot;: [
  803. &quot;timeline.seek&quot;,
  804. &quot;timeline.record&quot;,
  805. &quot;timeline.baseline&quot;,
  806. &quot;curve.axis&quot;,
  807. &quot;blueprint.palette&quot;,
  808. &quot;blueprint.add&quot;,
  809. &quot;blueprint.canvas&quot;
  810. ],
  811. &quot;projectIds&quot;: [
  812. &quot;230&quot;,
  813. &quot;231&quot;
  814. ],
  815. &quot;pose&quot;: {
  816. &quot;time&quot;: 0.9666666666666666,
  817. &quot;value&quot;: [
  818. 2.4166666666666665,
  819. -0.9666666666666666,
  820. 0
  821. ],
  822. &quot;actual&quot;: [
  823. 2.4166666666666665,
  824. -0.9666666666666666,
  825. 0
  826. ],
  827. &quot;base&quot;: [
  828. 0,
  829. 0,
  830. 0
  831. ]
  832. },
  833. &quot;recorded&quot;: {
  834. &quot;id&quot;: &quot;key-u60x1lh&quot;,
  835. &quot;time&quot;: 0.9666666666666666,
  836. &quot;value&quot;: [
  837. 2.4166666666666665,
  838. -0.9666666666666666,
  839. 0
  840. ],
  841. &quot;easing&quot;: &quot;easeInOut&quot;
  842. },
  843. &quot;curveAxis&quot;: {
  844. &quot;xAndYPathsDiffer&quot;: true,
  845. &quot;values&quot;: [
  846. 5,
  847. -2,
  848. 0
  849. ]
  850. },
  851. &quot;noMatchPreserved&quot;: true,
  852. &quot;baseline&quot;: {
  853. &quot;name&quot;: &quot;闭环工具补充-基准匹配-mtpjlmiy&quot;,
  854. &quot;timeline&quot;: {
  855. &quot;version&quot;: 1,
  856. &quot;duration&quot;: 12,
  857. &quot;currentTime&quot;: 0,
  858. &quot;loop&quot;: true,
  859. &quot;zoom&quot;: 1,
  860. &quot;tracks&quot;: [
  861. {
  862. &quot;id&quot;: &quot;bridge-front-outrigger-drop&quot;,
  863. &quot;name&quot;: &quot;前支腿下落支撑&quot;,
  864. &quot;targetId&quot;: &quot;bridge-front-outrigger&quot;,
  865. &quot;property&quot;: &quot;position&quot;,
  866. &quot;color&quot;: &quot;#ffd166&quot;,
  867. &quot;muted&quot;: false,
  868. &quot;keyframes&quot;: [
  869. {
  870. &quot;id&quot;: &quot;bfo-k0&quot;,
  871. &quot;time&quot;: 0,
  872. &quot;value&quot;: [
  873. 0,
  874. 0,
  875. 0
  876. ],
  877. &quot;easing&quot;: &quot;easeInOut&quot;
  878. },
  879. {
  880. &quot;id&quot;: &quot;bfo-k1&quot;,
  881. &quot;time&quot;: 2.4,
  882. &quot;value&quot;: [
  883. 0,
  884. -0.45,
  885. 0
  886. ],
  887. &quot;easing&quot;: &quot;easeInOut&quot;
  888. },
  889. {
  890. &quot;id&quot;: &quot;bfo-k2&quot;,
  891. &quot;time&quot;: 10,
  892. &quot;value&quot;: [
  893. 0,
  894. -0.45,
  895. 0
  896. ],
  897. &quot;easing&quot;: &quot;linear&quot;
  898. },
  899. {
  900. &quot;id&quot;: &quot;bfo-k3&quot;,
  901. &quot;time&quot;: 12,
  902. &quot;value&quot;: [
  903. 0,
  904. 0,
  905. 0
  906. ],
  907. &quot;easing&quot;: &quot;easeInOut&quot;
  908. }
  909. ]
  910. },
  911. {
  912. &quot;id&quot;: &quot;bridge-rear-outrigger-drop&quot;,
  913. &quot;name&quot;: &quot;后支腿下落支撑&quot;,
  914. &quot;targetId&quot;: &quot;bridge-rear-outrigger&quot;,
  915. &quot;property&quot;: &quot;position&quot;,
  916. &quot;color&quot;: &quot;#f4a261&quot;,
  917. &quot;muted&quot;: false,
  918. &quot;keyframes&quot;: [
  919. {
  920. &quot;id&quot;: &quot;bro-k0&quot;,
  921. &quot;time&quot;: 0,
  922. &quot;value&quot;: [
  923. 0,
  924. 0,
  925. 0
  926. ],
  927. &quot;easing&quot;: &quot;easeInOut&quot;
  928. },
  929. {
  930. &quot;id&quot;: &quot;bro-k1&quot;,
  931. &quot;time&quot;: 2.2,
  932. &quot;value&quot;: [
  933. 0,
  934. -0.19,
  935. 0
  936. ],
  937. &quot;easing&quot;: &quot;easeInOut&quot;
  938. },
  939. {
  940. &quot;id&quot;: &quot;bro-k2&quot;,
  941. &quot;time&quot;: 10,
  942. &quot;value&quot;: [
  943. 0,
  944. -0.19,
  945. 0
  946. ],
  947. &quot;easing&quot;: &quot;linear&quot;
  948. },
  949. {
  950. &quot;id&quot;: &quot;bro-k3&quot;,
  951. &quot;time&quot;: 12,
  952. &quot;value&quot;: [
  953. 0,
  954. 0,
  955. 0
  956. ],
  957. &quot;easing&quot;: &quot;easeInOut&quot;
  958. }
  959. ]
  960. },
  961. {
  962. &quot;id&quot;: &quot;bridge-rear-support-drop&quot;,
  963. &quot;name&quot;: &quot;后支座下落支撑&quot;,
  964. &quot;targetId&quot;: &quot;bridge-rear-support&quot;,
  965. &quot;property&quot;: &quot;position&quot;,
  966. &quot;color&quot;: &quot;#e76f51&quot;,
  967. &quot;muted&quot;: false,
  968. &quot;keyframes&quot;: [
  969. {
  970. &quot;id&quot;: &quot;brs-k0&quot;,
  971. &quot;time&quot;: 0,
  972. &quot;value&quot;: [
  973. 0,
  974. 0,
  975. 0
  976. ],
  977. &quot;easing&quot;: &quot;easeInOut&quot;
  978. },
  979. {
  980. &quot;id&quot;: &quot;brs-k1&quot;,
  981. &quot;time&quot;: 0.4,
  982. &quot;value&quot;: [
  983. 0,
  984. 0,
  985. 0
  986. ],
  987. &quot;easing&quot;: &quot;easeInOut&quot;
  988. },
  989. {
  990. &quot;id&quot;: &quot;brs-k2&quot;,
  991. &quot;time&quot;: 2.6,
  992. &quot;value&quot;: [
  993. 0,
  994. -0.25,
  995. 0
  996. ],
  997. &quot;easing&quot;: &quot;easeInOut&quot;
  998. },
  999. {
  1000. &quot;id&quot;: &quot;brs-k3&quot;,
  1001. &quot;time&quot;: 10.2,
  1002. &quot;value&quot;: [
  1003. 0,
  1004. -0.25,
  1005. 0
  1006. ],
  1007. &quot;easing&quot;: &quot;linear&quot;
  1008. },
  1009. {
  1010. &quot;id&quot;: &quot;brs-k4&quot;,
  1011. &quot;time&quot;: 12,
  1012. &quot;value&quot;: [
  1013. 0,
  1014. 0,
  1015. 0
  1016. ],
  1017. &quot;easing&quot;: &quot;easeInOut&quot;
  1018. }
  1019. ]
  1020. },
  1021. {
  1022. &quot;id&quot;: &quot;bridge-gantry-slew&quot;,
  1023. &quot;name&quot;: &quot;回转门架回转&quot;,
  1024. &quot;targetId&quot;: &quot;bridge-gantry&quot;,
  1025. &quot;property&quot;: &quot;rotation.y&quot;,
  1026. &quot;color&quot;: &quot;#2a9d8f&quot;,
  1027. &quot;muted&quot;: false,
  1028. &quot;keyframes&quot;: [
  1029. {
  1030. &quot;id&quot;: &quot;bgs-k0&quot;,
  1031. &quot;time&quot;: 0,
  1032. &quot;value&quot;: 0,
  1033. &quot;easing&quot;: &quot;easeInOut&quot;
  1034. },
  1035. {
  1036. &quot;id&quot;: &quot;bgs-k1&quot;,
  1037. &quot;time&quot;: 2.2,
  1038. &quot;value&quot;: 0,
  1039. &quot;easing&quot;: &quot;easeInOut&quot;
  1040. },
  1041. {
  1042. &quot;id&quot;: &quot;bgs-k2&quot;,
  1043. &quot;time&quot;: 4.8,
  1044. &quot;value&quot;: 0.24,
  1045. &quot;easing&quot;: &quot;easeInOut&quot;
  1046. },
  1047. {
  1048. &quot;id&quot;: &quot;bgs-k3&quot;,
  1049. &quot;time&quot;: 8.6,
  1050. &quot;value&quot;: 0.24,
  1051. &quot;easing&quot;: &quot;linear&quot;
  1052. },
  1053. {
  1054. &quot;id&quot;: &quot;bgs-k4&quot;,
  1055. &quot;time&quot;: 11.4,
  1056. &quot;value&quot;: 0,
  1057. &quot;easing&quot;: &quot;easeInOut&quot;
  1058. },
  1059. {
  1060. &quot;id&quot;: &quot;bgs-k5&quot;,
  1061. &quot;time&quot;: 12,
  1062. &quot;value&quot;: 0,
  1063. &quot;easing&quot;: &quot;easeInOut&quot;
  1064. }
  1065. ]
  1066. },
  1067. {
  1068. &quot;id&quot;: &quot;bridge-gantry-upper-luffing&quot;,
  1069. &quot;name&quot;: &quot;门架上臂变幅&quot;,
  1070. &quot;targetId&quot;: &quot;bridge-gantry-upper&quot;,
  1071. &quot;property&quot;: &quot;rotation.x&quot;,
  1072. &quot;color&quot;: &quot;#8a68e8&quot;,
  1073. &quot;muted&quot;: false,
  1074. &quot;keyframes&quot;: [
  1075. {
  1076. &quot;id&quot;: &quot;bgu-k0&quot;,
  1077. &quot;time&quot;: 0,
  1078. &quot;value&quot;: 0,
  1079. &quot;easing&quot;: &quot;easeInOut&quot;
  1080. },
  1081. {
  1082. &quot;id&quot;: &quot;bgu-k1&quot;,
  1083. &quot;time&quot;: 3,
  1084. &quot;value&quot;: 0,
  1085. &quot;easing&quot;: &quot;easeInOut&quot;
  1086. },
  1087. {
  1088. &quot;id&quot;: &quot;bgu-k2&quot;,
  1089. &quot;time&quot;: 5.4,
  1090. &quot;value&quot;: -0.22,
  1091. &quot;easing&quot;: &quot;easeInOut&quot;
  1092. },
  1093. {
  1094. &quot;id&quot;: &quot;bgu-k3&quot;,
  1095. &quot;time&quot;: 8.8,
  1096. &quot;value&quot;: -0.22,
  1097. &quot;easing&quot;: &quot;linear&quot;
  1098. },
  1099. {
  1100. &quot;id&quot;: &quot;bgu-k4&quot;,
  1101. &quot;time&quot;: 11.2,
  1102. &quot;value&quot;: 0,
  1103. &quot;easing&quot;: &quot;easeInOut&quot;
  1104. },
  1105. {
  1106. &quot;id&quot;: &quot;bgu-k5&quot;,
  1107. &quot;time&quot;: 12,
  1108. &quot;value&quot;: 0,
  1109. &quot;easing&quot;: &quot;easeInOut&quot;
  1110. }
  1111. ]
  1112. },
  1113. {
  1114. &quot;id&quot;: &quot;bridge-erection-frame-luffing&quot;,
  1115. &quot;name&quot;: &quot;后架设架起落(抬头 → 落桥)&quot;,
  1116. &quot;targetId&quot;: &quot;bridge-erection-frame&quot;,
  1117. &quot;property&quot;: &quot;rotation.x&quot;,
  1118. &quot;color&quot;: &quot;#4cc9f0&quot;,
  1119. &quot;muted&quot;: false,
  1120. &quot;keyframes&quot;: [
  1121. {
  1122. &quot;id&quot;: &quot;bef-k0&quot;,
  1123. &quot;time&quot;: 0,
  1124. &quot;value&quot;: 0,
  1125. &quot;easing&quot;: &quot;easeInOut&quot;
  1126. },
  1127. {
  1128. &quot;id&quot;: &quot;bef-k1&quot;,
  1129. &quot;time&quot;: 3.6,
  1130. &quot;value&quot;: 0,
  1131. &quot;easing&quot;: &quot;easeInOut&quot;
  1132. },
  1133. {
  1134. &quot;id&quot;: &quot;bef-k2&quot;,
  1135. &quot;time&quot;: 5,
  1136. &quot;value&quot;: -0.07,
  1137. &quot;easing&quot;: &quot;easeInOut&quot;
  1138. },
  1139. {
  1140. &quot;id&quot;: &quot;bef-k3&quot;,
  1141. &quot;time&quot;: 7.8,
  1142. &quot;value&quot;: 0.2,
  1143. &quot;easing&quot;: &quot;easeInOut&quot;
  1144. },
  1145. {
  1146. &quot;id&quot;: &quot;bef-k4&quot;,
  1147. &quot;time&quot;: 9.8,
  1148. &quot;value&quot;: 0.2,
  1149. &quot;easing&quot;: &quot;linear&quot;
  1150. },
  1151. {
  1152. &quot;id&quot;: &quot;bef-k5&quot;,
  1153. &quot;time&quot;: 11.6,
  1154. &quot;value&quot;: 0,
  1155. &quot;easing&quot;: &quot;easeInOut&quot;
  1156. },
  1157. {
  1158. &quot;id&quot;: &quot;bef-k6&quot;,
  1159. &quot;time&quot;: 12,
  1160. &quot;value&quot;: 0,
  1161. &quot;easing&quot;: &quot;easeInOut&quot;
  1162. }
  1163. ]
  1164. },
  1165. {
  1166. &quot;id&quot;: &quot;bridge-luffing-cylinder-follow&quot;,
  1167. &quot;name&quot;: &quot;变幅缸随动&quot;,
  1168. &quot;targetId&quot;: &quot;bridge-luffing-cylinder&quot;,
  1169. &quot;property&quot;: &quot;rotation.x&quot;,
  1170. &quot;color&quot;: &quot;#90be6d&quot;,
  1171. &quot;muted&quot;: false,
  1172. &quot;keyframes&quot;: [
  1173. {
  1174. &quot;id&quot;: &quot;blc-k0&quot;,
  1175. &quot;time&quot;: 0,
  1176. &quot;value&quot;: 0,
  1177. &quot;easing&quot;: &quot;easeInOut&quot;
  1178. },
  1179. {
  1180. &quot;id&quot;: &quot;blc-k1&quot;,
  1181. &quot;time&quot;: 3.6,
  1182. &quot;value&quot;: 0,
  1183. &quot;easing&quot;: &quot;easeInOut&quot;
  1184. },
  1185. {
  1186. &quot;id&quot;: &quot;blc-k2&quot;,
  1187. &quot;time&quot;: 5,
  1188. &quot;value&quot;: -0.03,
  1189. &quot;easing&quot;: &quot;easeInOut&quot;
  1190. },
  1191. {
  1192. &quot;id&quot;: &quot;blc-k3&quot;,
  1193. &quot;time&quot;: 7.8,
  1194. &quot;value&quot;: 0.09,
  1195. &quot;easing&quot;: &quot;easeInOut&quot;
  1196. },
  1197. {
  1198. &quot;id&quot;: &quot;blc-k4&quot;,
  1199. &quot;time&quot;: 9.8,
  1200. &quot;value&quot;: 0.09,
  1201. &quot;easing&quot;: &quot;linear&quot;
  1202. },
  1203. {
  1204. &quot;id&quot;: &quot;blc-k5&quot;,
  1205. &quot;time&quot;: 11.6,
  1206. &quot;value&quot;: 0,
  1207. &quot;easing&quot;: &quot;easeInOut&quot;
  1208. },
  1209. {
  1210. &quot;id&quot;: &quot;blc-k6&quot;,
  1211. &quot;time&quot;: 12,
  1212. &quot;value&quot;: 0,
  1213. &quot;easing&quot;: &quot;easeInOut&quot;
  1214. }
  1215. ]
  1216. },
  1217. {
  1218. &quot;id&quot;: &quot;bridge-carriage-travel&quot;,
  1219. &quot;name&quot;: &quot;移动架沿滑道后行&quot;,
  1220. &quot;targetId&quot;: &quot;bridge-carriage&quot;,
  1221. &quot;property&quot;: &quot;position&quot;,
  1222. &quot;color&quot;: &quot;#32b8e6&quot;,
  1223. &quot;muted&quot;: false,
  1224. &quot;keyframes&quot;: [
  1225. {
  1226. &quot;id&quot;: &quot;bct-k0&quot;,
  1227. &quot;time&quot;: 0,
  1228. &quot;value&quot;: [
  1229. 0,
  1230. 0,
  1231. 0
  1232. ],
  1233. &quot;easing&quot;: &quot;easeInOut&quot;
  1234. },
  1235. {
  1236. &quot;id&quot;: &quot;bct-k1&quot;,
  1237. &quot;time&quot;: 5.4,
  1238. &quot;value&quot;: [
  1239. 0,
  1240. 0,
  1241. 0
  1242. ],
  1243. &quot;easing&quot;: &quot;easeInOut&quot;
  1244. },
  1245. {
  1246. &quot;id&quot;: &quot;bct-k2&quot;,
  1247. &quot;time&quot;: 8.4,
  1248. &quot;value&quot;: [
  1249. 0,
  1250. 0,
  1251. -0.42
  1252. ],
  1253. &quot;easing&quot;: &quot;easeInOut&quot;
  1254. },
  1255. {
  1256. &quot;id&quot;: &quot;bct-k3&quot;,
  1257. &quot;time&quot;: 10,
  1258. &quot;value&quot;: [
  1259. 0,
  1260. 0,
  1261. -0.42
  1262. ],
  1263. &quot;easing&quot;: &quot;linear&quot;
  1264. },
  1265. {
  1266. &quot;id&quot;: &quot;bct-k4&quot;,
  1267. &quot;time&quot;: 12,
  1268. &quot;value&quot;: [
  1269. 0,
  1270. 0,
  1271. 0
  1272. ],
  1273. &quot;easing&quot;: &quot;easeInOut&quot;
  1274. }
  1275. ]
  1276. },
  1277. {
  1278. &quot;id&quot;: &quot;bridge-launch-pinion-drive&quot;,
  1279. &quot;name&quot;: &quot;导梁销齿轮驱动&quot;,
  1280. &quot;targetId&quot;: &quot;bridge-launch-pinion&quot;,
  1281. &quot;property&quot;: &quot;rotation.x&quot;,
  1282. &quot;color&quot;: &quot;#f9c74f&quot;,
  1283. &quot;muted&quot;: false,
  1284. &quot;keyframes&quot;: [
  1285. {
  1286. &quot;id&quot;: &quot;blp-k0&quot;,
  1287. &quot;time&quot;: 0,
  1288. &quot;value&quot;: 0,
  1289. &quot;easing&quot;: &quot;linear&quot;
  1290. },
  1291. {
  1292. &quot;id&quot;: &quot;blp-k1&quot;,
  1293. &quot;time&quot;: 5.4,
  1294. &quot;value&quot;: 0,
  1295. &quot;easing&quot;: &quot;linear&quot;
  1296. },
  1297. {
  1298. &quot;id&quot;: &quot;blp-k2&quot;,
  1299. &quot;time&quot;: 8.4,
  1300. &quot;value&quot;: 5.2,
  1301. &quot;easing&quot;: &quot;linear&quot;
  1302. },
  1303. {
  1304. &quot;id&quot;: &quot;blp-k3&quot;,
  1305. &quot;time&quot;: 10,
  1306. &quot;value&quot;: 5.2,
  1307. &quot;easing&quot;: &quot;linear&quot;
  1308. },
  1309. {
  1310. &quot;id&quot;: &quot;blp-k4&quot;,
  1311. &quot;time&quot;: 12,
  1312. &quot;value&quot;: 0,
  1313. &quot;easing&quot;: &quot;linear&quot;
  1314. }
  1315. ]
  1316. },
  1317. {
  1318. &quot;id&quot;: &quot;bridge-front-cradle-luffing&quot;,
  1319. &quot;name&quot;: &quot;前托架抬头&quot;,
  1320. &quot;targetId&quot;: &quot;bridge-front-cradle&quot;,
  1321. &quot;property&quot;: &quot;rotation.x&quot;,
  1322. &quot;color&quot;: &quot;#ff9f2f&quot;,
  1323. &quot;muted&quot;: false,
  1324. &quot;keyframes&quot;: [
  1325. {
  1326. &quot;id&quot;: &quot;bfc-k0&quot;,
  1327. &quot;time&quot;: 0,
  1328. &quot;value&quot;: 0,
  1329. &quot;easing&quot;: &quot;easeInOut&quot;
  1330. },
  1331. {
  1332. &quot;id&quot;: &quot;bfc-k1&quot;,
  1333. &quot;time&quot;: 6.8,
  1334. &quot;value&quot;: 0,
  1335. &quot;easing&quot;: &quot;easeInOut&quot;
  1336. },
  1337. {
  1338. &quot;id&quot;: &quot;bfc-k2&quot;,
  1339. &quot;time&quot;: 9,
  1340. &quot;value&quot;: 0.12,
  1341. &quot;easing&quot;: &quot;easeInOut&quot;
  1342. },
  1343. {
  1344. &quot;id&quot;: &quot;bfc-k3&quot;,
  1345. &quot;time&quot;: 10.4,
  1346. &quot;value&quot;: 0.12,
  1347. &quot;easing&quot;: &quot;linear&quot;
  1348. },
  1349. {
  1350. &quot;id&quot;: &quot;bfc-k4&quot;,
  1351. &quot;time&quot;: 11.8,
  1352. &quot;value&quot;: 0,
  1353. &quot;easing&quot;: &quot;easeInOut&quot;
  1354. },
  1355. {
  1356. &quot;id&quot;: &quot;bfc-k5&quot;,
  1357. &quot;time&quot;: 12,
  1358. &quot;value&quot;: 0,
  1359. &quot;easing&quot;: &quot;easeInOut&quot;
  1360. }
  1361. ]
  1362. },
  1363. {
  1364. &quot;id&quot;: &quot;bridge-front-pusher-extend&quot;,
  1365. &quot;name&quot;: &quot;前推送装置送桥&quot;,
  1366. &quot;targetId&quot;: &quot;bridge-front-pusher&quot;,
  1367. &quot;property&quot;: &quot;position&quot;,
  1368. &quot;color&quot;: &quot;#ef476f&quot;,
  1369. &quot;muted&quot;: false,
  1370. &quot;keyframes&quot;: [
  1371. {
  1372. &quot;id&quot;: &quot;bfp-k0&quot;,
  1373. &quot;time&quot;: 0,
  1374. &quot;value&quot;: [
  1375. 0,
  1376. 0,
  1377. 0
  1378. ],
  1379. &quot;easing&quot;: &quot;easeInOut&quot;
  1380. },
  1381. {
  1382. &quot;id&quot;: &quot;bfp-k1&quot;,
  1383. &quot;time&quot;: 7.2,
  1384. &quot;value&quot;: [
  1385. 0,
  1386. 0,
  1387. 0
  1388. ],
  1389. &quot;easing&quot;: &quot;easeInOut&quot;
  1390. },
  1391. {
  1392. &quot;id&quot;: &quot;bfp-k2&quot;,
  1393. &quot;time&quot;: 9.4,
  1394. &quot;value&quot;: [
  1395. 0,
  1396. 0,
  1397. 0.34
  1398. ],
  1399. &quot;easing&quot;: &quot;easeInOut&quot;
  1400. },
  1401. {
  1402. &quot;id&quot;: &quot;bfp-k3&quot;,
  1403. &quot;time&quot;: 10.6,
  1404. &quot;value&quot;: [
  1405. 0,
  1406. 0,
  1407. 0.34
  1408. ],
  1409. &quot;easing&quot;: &quot;linear&quot;
  1410. },
  1411. {
  1412. &quot;id&quot;: &quot;bfp-k4&quot;,
  1413. &quot;time&quot;: 12,
  1414. &quot;value&quot;: [
  1415. 0,
  1416. 0,
  1417. 0
  1418. ],
  1419. &quot;easing&quot;: &quot;easeInOut&quot;
  1420. }
  1421. ]
  1422. },
  1423. {
  1424. &quot;id&quot;: &quot;bridge-feed-pinion-drive&quot;,
  1425. &quot;name&quot;: &quot;前推送销齿轮驱动&quot;,
  1426. &quot;targetId&quot;: &quot;bridge-feed-pinion&quot;,
  1427. &quot;property&quot;: &quot;rotation.x&quot;,
  1428. &quot;color&quot;: &quot;#c77dff&quot;,
  1429. &quot;muted&quot;: false,
  1430. &quot;keyframes&quot;: [
  1431. {
  1432. &quot;id&quot;: &quot;bfd-k0&quot;,
  1433. &quot;time&quot;: 0,
  1434. &quot;value&quot;: 0,
  1435. &quot;easing&quot;: &quot;linear&quot;
  1436. },
  1437. {
  1438. &quot;id&quot;: &quot;bfd-k1&quot;,
  1439. &quot;time&quot;: 7.2,
  1440. &quot;value&quot;: 0,
  1441. &quot;easing&quot;: &quot;linear&quot;
  1442. },
  1443. {
  1444. &quot;id&quot;: &quot;bfd-k2&quot;,
  1445. &quot;time&quot;: 9.4,
  1446. &quot;value&quot;: 4,
  1447. &quot;easing&quot;: &quot;linear&quot;
  1448. },
  1449. {
  1450. &quot;id&quot;: &quot;bfd-k3&quot;,
  1451. &quot;time&quot;: 10.6,
  1452. &quot;value&quot;: 4,
  1453. &quot;easing&quot;: &quot;linear&quot;
  1454. },
  1455. {
  1456. &quot;id&quot;: &quot;bfd-k4&quot;,
  1457. &quot;time&quot;: 12,
  1458. &quot;value&quot;: 0,
  1459. &quot;easing&quot;: &quot;linear&quot;
  1460. }
  1461. ]
  1462. }
  1463. ]
  1464. },
  1465. &quot;resolved&quot;: true
  1466. },
  1467. &quot;addedNode&quot;: {
  1468. &quot;id&quot;: &quot;node-mtpjlj3c-n13gc&quot;,
  1469. &quot;type&quot;: &quot;message&quot;,
  1470. &quot;title&quot;: &quot;操作提示&quot;,
  1471. &quot;x&quot;: 440,
  1472. &quot;y&quot;: 160,
  1473. &quot;params&quot;: {
  1474. &quot;title&quot;: &quot;操作提示&quot;,
  1475. &quot;text&quot;: &quot;请观察铲斗与动臂的联动过程&quot;,
  1476. &quot;level&quot;: &quot;info&quot;
  1477. }
  1478. },
  1479. &quot;draggedNode&quot;: {
  1480. &quot;id&quot;: &quot;node-mtpjlj9e-sko2s&quot;,
  1481. &quot;type&quot;: &quot;wait&quot;,
  1482. &quot;title&quot;: &quot;等待&quot;,
  1483. &quot;x&quot;: -40,
  1484. &quot;y&quot;: -170,
  1485. &quot;params&quot;: {
  1486. &quot;duration&quot;: 600
  1487. }
  1488. },
  1489. &quot;canvasPreservedGraph&quot;: true,
  1490. &quot;scope&quot;: &quot;真实模型编辑参数/基准轨道生成验收,不构成装备操作或维修指导。桥梁原工程94仅GET和copy。&quot;
  1491. }
  1492. }</pre></details><details><summary><a href="evidence/truck-blueprint-ui.json">evidence/truck-blueprint-ui.json</a> <span class="badge pass">已验证</span></summary><pre>{
  1493. &quot;time&quot;: &quot;2026-09-06T08:21:37.144Z&quot;,
  1494. &quot;data&quot;: {
  1495. &quot;status&quot;: &quot;PASS&quot;,
  1496. &quot;kind&quot;: &quot;e2e+runtime-read&quot;,
  1497. &quot;testTitle&quot;: &quot;蓝图真实节点库与端口拖线:七种参数、内部边复制/剪切、撤销重做及保存&quot;,
  1498. &quot;featureIds&quot;: [
  1499. &quot;blueprint.parameters&quot;,
  1500. &quot;blueprint.move&quot;,
  1501. &quot;blueprint.connect&quot;,
  1502. &quot;blueprint.delete&quot;,
  1503. &quot;blueprint.copy&quot;,
  1504. &quot;blueprint.run&quot;,
  1505. &quot;blueprint.stop&quot;,
  1506. &quot;blueprint.reset&quot;,
  1507. &quot;blueprint.timeline&quot;,
  1508. &quot;blueprint.wait&quot;,
  1509. &quot;blueprint.highlight&quot;,
  1510. &quot;blueprint.message&quot;,
  1511. &quot;blueprint.finish&quot;,
  1512. &quot;project.undo&quot;,
  1513. &quot;project.redo&quot;
  1514. ],
  1515. &quot;scope&quot;: &quot;节点库点选添加及实际拖动/接线/执行;不把点选当成节点拖入,不把适应画布当成鼠标平移缩放全部已验。&quot;,
  1516. &quot;projectId&quot;: &quot;169&quot;,
  1517. &quot;graph&quot;: {
  1518. &quot;nodes&quot;: [
  1519. {
  1520. &quot;id&quot;: &quot;node-mtpjlx7c-sgcyx&quot;,
  1521. &quot;type&quot;: &quot;trigger-click&quot;,
  1522. &quot;title&quot;: &quot;闭环-点击触发&quot;,
  1523. &quot;x&quot;: 160,
  1524. &quot;y&quot;: -120,
  1525. &quot;params&quot;: {
  1526. &quot;event&quot;: &quot;click&quot;,
  1527. &quot;target&quot;: &quot;model-imported-model_mto6wi6k_08-cesiummilktruck-3&quot;
  1528. }
  1529. },
  1530. {
  1531. &quot;id&quot;: &quot;node-mtpjlxj9-y3g3v&quot;,
  1532. &quot;type&quot;: &quot;play-timeline&quot;,
  1533. &quot;title&quot;: &quot;闭环-播放时间轴&quot;,
  1534. &quot;x&quot;: 420,
  1535. &quot;y&quot;: -120,
  1536. &quot;params&quot;: {
  1537. &quot;clip&quot;: &quot;牛奶卡车曲线联动&quot;,
  1538. &quot;from&quot;: 8,
  1539. &quot;speed&quot;: 2,
  1540. &quot;waitForEnd&quot;: true
  1541. }
  1542. },
  1543. {
  1544. &quot;id&quot;: &quot;node-mtpjlxxe-ond97&quot;,
  1545. &quot;type&quot;: &quot;wait&quot;,
  1546. &quot;title&quot;: &quot;闭环-等待&quot;,
  1547. &quot;x&quot;: 680,
  1548. &quot;y&quot;: -120,
  1549. &quot;params&quot;: {
  1550. &quot;duration&quot;: 100
  1551. }
  1552. },
  1553. {
  1554. &quot;id&quot;: &quot;node-mtpjlyci-4c5oi&quot;,
  1555. &quot;type&quot;: &quot;highlight&quot;,
  1556. &quot;title&quot;: &quot;闭环-高亮部件&quot;,
  1557. &quot;x&quot;: 160,
  1558. &quot;y&quot;: 70,
  1559. &quot;params&quot;: {
  1560. &quot;target&quot;: &quot;model-imported-model_mto6wi6k_08-cesiummilktruck-3&quot;,
  1561. &quot;color&quot;: &quot;#ff8800&quot;,
  1562. &quot;pulse&quot;: false
  1563. }
  1564. },
  1565. {
  1566. &quot;id&quot;: &quot;node-mtpjlyuw-164xj&quot;,
  1567. &quot;type&quot;: &quot;message&quot;,
  1568. &quot;title&quot;: &quot;闭环-操作提示&quot;,
  1569. &quot;x&quot;: 420,
  1570. &quot;y&quot;: 70,
  1571. &quot;params&quot;: {
  1572. &quot;title&quot;: &quot;卡车模型闭环提示&quot;,
  1573. &quot;text&quot;: &quot;检查真实目标高亮、时间轴完成和条件出口。&quot;,
  1574. &quot;level&quot;: &quot;success&quot;
  1575. }
  1576. },
  1577. {
  1578. &quot;id&quot;: &quot;node-mtpjlz9t-p124m&quot;,
  1579. &quot;type&quot;: &quot;condition&quot;,
  1580. &quot;title&quot;: &quot;闭环-条件判断&quot;,
  1581. &quot;x&quot;: 680,
  1582. &quot;y&quot;: 70,
  1583. &quot;params&quot;: {
  1584. &quot;variable&quot;: &quot;timelineComplete&quot;,
  1585. &quot;operator&quot;: &quot;==&quot;,
  1586. &quot;value&quot;: true
  1587. }
  1588. },
  1589. {
  1590. &quot;id&quot;: &quot;node-mtpjlznf-cxlzk&quot;,
  1591. &quot;type&quot;: &quot;finish&quot;,
  1592. &quot;title&quot;: &quot;闭环-流程完成&quot;,
  1593. &quot;x&quot;: 420,
  1594. &quot;y&quot;: 260,
  1595. &quot;params&quot;: {
  1596. &quot;result&quot;: &quot;success&quot;,
  1597. &quot;text&quot;: &quot;牛奶卡车蓝图验证完成&quot;
  1598. }
  1599. }
  1600. ],
  1601. &quot;edges&quot;: [
  1602. {
  1603. &quot;id&quot;: &quot;edge-mtpjm04u-tt0qb&quot;,
  1604. &quot;from&quot;: {
  1605. &quot;node&quot;: &quot;node-mtpjlx7c-sgcyx&quot;,
  1606. &quot;port&quot;: &quot;then&quot;
  1607. },
  1608. &quot;to&quot;: {
  1609. &quot;node&quot;: &quot;node-mtpjlxj9-y3g3v&quot;,
  1610. &quot;port&quot;: &quot;in&quot;
  1611. }
  1612. },
  1613. {
  1614. &quot;id&quot;: &quot;edge-mtpjm0bc-mnf7c&quot;,
  1615. &quot;from&quot;: {
  1616. &quot;node&quot;: &quot;node-mtpjlxj9-y3g3v&quot;,
  1617. &quot;port&quot;: &quot;then&quot;
  1618. },
  1619. &quot;to&quot;: {
  1620. &quot;node&quot;: &quot;node-mtpjlxxe-ond97&quot;,
  1621. &quot;port&quot;: &quot;in&quot;
  1622. }
  1623. },
  1624. {
  1625. &quot;id&quot;: &quot;edge-mtpjm0gx-mu6ys&quot;,
  1626. &quot;from&quot;: {
  1627. &quot;node&quot;: &quot;node-mtpjlxxe-ond97&quot;,
  1628. &quot;port&quot;: &quot;then&quot;
  1629. },
  1630. &quot;to&quot;: {
  1631. &quot;node&quot;: &quot;node-mtpjlyci-4c5oi&quot;,
  1632. &quot;port&quot;: &quot;in&quot;
  1633. }
  1634. },
  1635. {
  1636. &quot;id&quot;: &quot;edge-mtpjm0nr-y06n7&quot;,
  1637. &quot;from&quot;: {
  1638. &quot;node&quot;: &quot;node-mtpjlyci-4c5oi&quot;,
  1639. &quot;port&quot;: &quot;then&quot;
  1640. },
  1641. &quot;to&quot;: {
  1642. &quot;node&quot;: &quot;node-mtpjlyuw-164xj&quot;,
  1643. &quot;port&quot;: &quot;in&quot;
  1644. }
  1645. },
  1646. {
  1647. &quot;id&quot;: &quot;edge-mtpjm0ts-px732&quot;,
  1648. &quot;from&quot;: {
  1649. &quot;node&quot;: &quot;node-mtpjlyuw-164xj&quot;,
  1650. &quot;port&quot;: &quot;then&quot;
  1651. },
  1652. &quot;to&quot;: {
  1653. &quot;node&quot;: &quot;node-mtpjlz9t-p124m&quot;,
  1654. &quot;port&quot;: &quot;in&quot;
  1655. }
  1656. },
  1657. {
  1658. &quot;id&quot;: &quot;edge-mtpjm0zf-sa3h2&quot;,
  1659. &quot;from&quot;: {
  1660. &quot;node&quot;: &quot;node-mtpjlz9t-p124m&quot;,
  1661. &quot;port&quot;: &quot;true&quot;
  1662. },
  1663. &quot;to&quot;: {
  1664. &quot;node&quot;: &quot;node-mtpjlznf-cxlzk&quot;,
  1665. &quot;port&quot;: &quot;in&quot;
  1666. }
  1667. }
  1668. ],
  1669. &quot;running&quot;: false,
  1670. &quot;logs&quot;: [
  1671. {
  1672. &quot;time&quot;: &quot;16:21:35&quot;,
  1673. &quot;message&quot;: &quot;运行状态已重置&quot;,
  1674. &quot;level&quot;: &quot;system&quot;,
  1675. &quot;nodeId&quot;: null
  1676. }
  1677. ]
  1678. },
  1679. &quot;completedLog&quot;: [
  1680. {
  1681. &quot;time&quot;: &quot;16:21:25&quot;,
  1682. &quot;message&quot;: &quot;蓝图编辑器就绪 · 7 类节点已加载&quot;,
  1683. &quot;level&quot;: &quot;system&quot;,
  1684. &quot;nodeId&quot;: null
  1685. },
  1686. {
  1687. &quot;time&quot;: &quot;16:21:33&quot;,
  1688. &quot;message&quot;: &quot;开始执行 · 闭环-点击触发&quot;,
  1689. &quot;level&quot;: &quot;run&quot;,
  1690. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  1691. },
  1692. {
  1693. &quot;time&quot;: &quot;16:21:33&quot;,
  1694. &quot;message&quot;: &quot;执行节点:闭环-点击触发&quot;,
  1695. &quot;level&quot;: &quot;run&quot;,
  1696. &quot;nodeId&quot;: &quot;node-mtpjlx7c-sgcyx&quot;
  1697. },
  1698. {
  1699. &quot;time&quot;: &quot;16:21:33&quot;,
  1700. &quot;message&quot;: &quot;执行节点:闭环-播放时间轴&quot;,
  1701. &quot;level&quot;: &quot;run&quot;,
  1702. &quot;nodeId&quot;: &quot;node-mtpjlxj9-y3g3v&quot;
  1703. },
  1704. {
  1705. &quot;time&quot;: &quot;16:21:33&quot;,
  1706. &quot;message&quot;: &quot;执行节点:闭环-等待&quot;,
  1707. &quot;level&quot;: &quot;run&quot;,
  1708. &quot;nodeId&quot;: &quot;node-mtpjlxxe-ond97&quot;
  1709. },
  1710. {
  1711. &quot;time&quot;: &quot;16:21:33&quot;,
  1712. &quot;message&quot;: &quot;执行节点:闭环-高亮部件&quot;,
  1713. &quot;level&quot;: &quot;run&quot;,
  1714. &quot;nodeId&quot;: &quot;node-mtpjlyci-4c5oi&quot;
  1715. },
  1716. {
  1717. &quot;time&quot;: &quot;16:21:34&quot;,
  1718. &quot;message&quot;: &quot;执行节点:闭环-操作提示&quot;,
  1719. &quot;level&quot;: &quot;run&quot;,
  1720. &quot;nodeId&quot;: &quot;node-mtpjlyuw-164xj&quot;
  1721. },
  1722. {
  1723. &quot;time&quot;: &quot;16:21:35&quot;,
  1724. &quot;message&quot;: &quot;执行节点:闭环-条件判断&quot;,
  1725. &quot;level&quot;: &quot;run&quot;,
  1726. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  1727. },
  1728. {
  1729. &quot;time&quot;: &quot;16:21:35&quot;,
  1730. &quot;message&quot;: &quot;条件结果:是 / TRUE&quot;,
  1731. &quot;level&quot;: &quot;success&quot;,
  1732. &quot;nodeId&quot;: &quot;node-mtpjlz9t-p124m&quot;
  1733. },
  1734. {
  1735. &quot;time&quot;: &quot;16:21:35&quot;,
  1736. &quot;message&quot;: &quot;执行节点:闭环-流程完成&quot;,
  1737. &quot;level&quot;: &quot;run&quot;,
  1738. &quot;nodeId&quot;: &quot;node-mtpjlznf-cxlzk&quot;
  1739. },
  1740. {
  1741. &quot;time&quot;: &quot;16:21:35&quot;,
  1742. &quot;message&quot;: &quot;蓝图执行完成 · 7 个节点&quot;,
  1743. &quot;level&quot;: &quot;success&quot;,
  1744. &quot;nodeId&quot;: null
  1745. }
  1746. ],
  1747. &quot;actions&quot;: &quot;真实节点库/参数控件/端口拖线/复制剪切粘贴/删除/撤销重做/运行停止重置/保存&quot;,
  1748. &quot;boundaries&quot;: &quot;200 步循环保护由独立 Node 回归覆盖;本浏览器流程不注入假图或替换执行 handler。&quot;
  1749. }
  1750. }</pre></details><details><summary><a href="evidence/truck-timeline-curve.json">evidence/truck-timeline-curve.json</a> <span class="badge pass">已验证</span></summary><pre>{
  1751. &quot;time&quot;: &quot;2026-09-06T08:21:02.898Z&quot;,
  1752. &quot;data&quot;: {
  1753. &quot;status&quot;: &quot;PASS&quot;,
  1754. &quot;kind&quot;: &quot;e2e+runtime-read&quot;,
  1755. &quot;testTitle&quot;: &quot;时间轴真实控件:轨道/关键帧/播放与曲线 5 插值,保存后重新加载一致&quot;,
  1756. &quot;featureIds&quot;: [
  1757. &quot;timeline.play&quot;,
  1758. &quot;timeline.stop&quot;,
  1759. &quot;timeline.loop&quot;,
  1760. &quot;timeline.key-nav&quot;,
  1761. &quot;timeline.add-track&quot;,
  1762. &quot;timeline.remove-track&quot;,
  1763. &quot;timeline.target&quot;,
  1764. &quot;timeline.property&quot;,
  1765. &quot;timeline.mute&quot;,
  1766. &quot;timeline.add-key&quot;,
  1767. &quot;timeline.delete-key&quot;,
  1768. &quot;timeline.drag-key&quot;,
  1769. &quot;timeline.zoom&quot;,
  1770. &quot;timeline.curve&quot;,
  1771. &quot;curve.time&quot;,
  1772. &quot;curve.value&quot;,
  1773. &quot;curve.easing&quot;
  1774. ],
  1775. &quot;scope&quot;: &quot;真实控件和指针操作,运行时读取数值校验;curve.axis仅切换无数值独立断言,timeline.seek播放头与Alt吸附未在本例覆盖。&quot;,
  1776. &quot;projectId&quot;: &quot;169&quot;,
  1777. &quot;actions&quot;: &quot;真实 DOM 轨道/帧增删、关键帧指针拖移、播放控件、曲线输入和保存重开&quot;,
  1778. &quot;restored&quot;: {
  1779. &quot;id&quot;: &quot;track-0-che4ljm&quot;,
  1780. &quot;name&quot;: &quot;新轨道 6&quot;,
  1781. &quot;targetId&quot;: &quot;interaction-5f7e4bee&quot;,
  1782. &quot;property&quot;: &quot;position&quot;,
  1783. &quot;color&quot;: &quot;#ffb22e&quot;,
  1784. &quot;muted&quot;: false,
  1785. &quot;keyframes&quot;: [
  1786. {
  1787. &quot;id&quot;: &quot;key-0-0-mi1ztwf&quot;,
  1788. &quot;time&quot;: 0,
  1789. &quot;value&quot;: [
  1790. 0,
  1791. 0,
  1792. 0
  1793. ],
  1794. &quot;easing&quot;: &quot;easeInOut&quot;
  1795. },
  1796. {
  1797. &quot;id&quot;: &quot;key-zi8i3f7&quot;,
  1798. &quot;time&quot;: 2,
  1799. &quot;value&quot;: [
  1800. 5,
  1801. 0,
  1802. 0
  1803. ],
  1804. &quot;easing&quot;: &quot;easeInOut&quot;
  1805. },
  1806. {
  1807. &quot;id&quot;: &quot;key-0-1-2lnk2wi&quot;,
  1808. &quot;time&quot;: 8,
  1809. &quot;value&quot;: [
  1810. 0,
  1811. 0,
  1812. 0
  1813. ],
  1814. &quot;easing&quot;: &quot;easeInOut&quot;
  1815. }
  1816. ]
  1817. },
  1818. &quot;interpolationSamples&quot;: {
  1819. &quot;linear&quot;: 1.25,
  1820. &quot;easeInOut&quot;: 0.625,
  1821. &quot;easeIn&quot;: 0.3125,
  1822. &quot;easeOut&quot;: 2.1875,
  1823. &quot;step&quot;: 0
  1824. },
  1825. &quot;excluded&quot;: [
  1826. &quot;未新增 solo 能力&quot;,
  1827. &quot;未将原生 GLB 动画片段当成多条编辑时间轴&quot;
  1828. ]
  1829. }
  1830. }</pre></details><details><summary><a href="evidence/viewport.json">evidence/viewport.json</a> <span class="badge pass">已验证</span></summary><pre>{
  1831. &quot;time&quot;: &quot;2026-09-06T08:22:14.169Z&quot;,
  1832. &quot;data&quot;: {
  1833. &quot;status&quot;: &quot;PASS&quot;,
  1834. &quot;kind&quot;: &quot;e2e&quot;,
  1835. &quot;testTitle&quot;: &quot;场景树搜索、可见性、选择、视口工具、原生动画与截图&quot;,
  1836. &quot;featureIds&quot;: [
  1837. &quot;tree.search&quot;,
  1838. &quot;tree.visibility&quot;,
  1839. &quot;selection.sync&quot;,
  1840. &quot;view.grid&quot;,
  1841. &quot;view.pbr&quot;,
  1842. &quot;view.wireframe&quot;,
  1843. &quot;view.outline&quot;,
  1844. &quot;view.perspective&quot;,
  1845. &quot;view.preview&quot;,
  1846. &quot;view.snapshot&quot;,
  1847. &quot;timeline.native&quot;
  1848. ],
  1849. &quot;scope&quot;: &quot;树搜索、对象隐藏刷新、轮廓及视图开关、原生动画和PNG下载。移动/旋转/缩放只切换模式,真实gizmo拖动仍需补验;聚焦未做几何断言。&quot;,
  1850. &quot;clips&quot;: 3,
  1851. &quot;nativeClipPersisted&quot;: true,
  1852. &quot;hiddenObjectPersisted&quot;: true,
  1853. &quot;snapshot&quot;: &quot;装备模型编辑工具_1788682931740.png&quot;
  1854. }
  1855. }</pre></details></article>
  1856. <article class="panel"><h3>构建、聚焦单测与版本检查</h3><p><a href="validation.json">完整验证记录</a>。单测/合同测试不并入真实 E2E 数量。</p><pre>{
  1857. &quot;time&quot;: &quot;2026-09-06T08:28:23.891Z&quot;,
  1858. &quot;status&quot;: &quot;PASS&quot;,
  1859. &quot;e2eComplete&quot;: true,
  1860. &quot;checks&quot;: [
  1861. {
  1862. &quot;name&quot;: &quot;装备模型编辑回归&quot;,
  1863. &quot;command&quot;: &quot;node --test (8 model editor test files)&quot;,
  1864. &quot;tests&quot;: 54,
  1865. &quot;status&quot;: &quot;PASS&quot;,
  1866. &quot;failures&quot;: 0,
  1867. &quot;exitCode&quot;: 0
  1868. },
  1869. {
  1870. &quot;name&quot;: &quot;权限桥新建、脏状态和只读键盘回归&quot;,
  1871. &quot;command&quot;: &quot;node --test tools/content-permissions.test.mjs&quot;,
  1872. &quot;tests&quot;: 14,
  1873. &quot;status&quot;: &quot;PASS&quot;,
  1874. &quot;failures&quot;: 0,
  1875. &quot;exitCode&quot;: 0
  1876. },
  1877. {
  1878. &quot;name&quot;: &quot;报告证据归属与附件校验回归&quot;,
  1879. &quot;command&quot;: &quot;node --test tools/model-editor-report-evidence.test.mjs&quot;,
  1880. &quot;tests&quot;: 7,
  1881. &quot;status&quot;: &quot;PASS&quot;,
  1882. &quot;failures&quot;: 0,
  1883. &quot;exitCode&quot;: 0
  1884. },
  1885. {
  1886. &quot;name&quot;: &quot;实际 Kingbase 驱动正常检查与隔离网络无响应验证&quot;,
  1887. &quot;command&quot;: &quot;KingbaseValidationProbe (isolated loopback TCP proxy, SELECT 1 only)&quot;,
  1888. &quot;evidence&quot;: &quot;data/kingbase-validation-probe-result.json&quot;,
  1889. &quot;tests&quot;: 3,
  1890. &quot;status&quot;: &quot;PASS&quot;,
  1891. &quot;failures&quot;: 0,
  1892. &quot;exitCode&quot;: 0
  1893. },
  1894. {
  1895. &quot;name&quot;: &quot;Auth / Tran 完整构建与测试&quot;,
  1896. &quot;command&quot;: &quot;mvn -pl ut_auth,ut_tran -am package&quot;,
  1897. &quot;tests&quot;: 476,
  1898. &quot;moduleTests&quot;: [
  1899. 120,
  1900. 356
  1901. ],
  1902. &quot;status&quot;: &quot;PASS&quot;,
  1903. &quot;failures&quot;: 0,
  1904. &quot;exitCode&quot;: 0
  1905. },
  1906. {
  1907. &quot;name&quot;: &quot;Web 构建和 iframe 产物一致性&quot;,
  1908. &quot;command&quot;: &quot;pnpm run build&quot;,
  1909. &quot;warning&quot;: &quot;既有大包体积提示;构建及10项public/dist哈希校验通过&quot;,
  1910. &quot;status&quot;: &quot;PASS&quot;,
  1911. &quot;failures&quot;: 0,
  1912. &quot;exitCode&quot;: 0
  1913. },
  1914. {
  1915. &quot;name&quot;: &quot;6 E2E specs strict TypeScript&quot;,
  1916. &quot;command&quot;: &quot;tsc --noEmit --strict (closure specs, helper, config)&quot;,
  1917. &quot;status&quot;: &quot;PASS&quot;,
  1918. &quot;failures&quot;: 0,
  1919. &quot;exitCode&quot;: 0
  1920. }
  1921. ],
  1922. &quot;coverage&quot;: [
  1923. {
  1924. &quot;title&quot;: &quot;resource catalog startup renders all model/environment cards and binds every action with a real DOM&quot;,
  1925. &quot;featureIds&quot;: [
  1926. &quot;resource.catalog&quot;
  1927. ],
  1928. &quot;scope&quot;: &quot;真实 DOM 渲染、卡片绑定、空目录及 busy 保护;不包含 GLB 网络加载。&quot;,
  1929. &quot;status&quot;: &quot;PASS&quot;,
  1930. &quot;kind&quot;: &quot;unit&quot;,
  1931. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  1932. },
  1933. {
  1934. &quot;title&quot;: &quot;curve edits real scalar key values, time and interpolation, persisting through document reload&quot;,
  1935. &quot;featureIds&quot;: [
  1936. &quot;timeline.curve&quot;,
  1937. &quot;curve.time&quot;,
  1938. &quot;curve.value&quot;,
  1939. &quot;curve.easing&quot;
  1940. ],
  1941. &quot;scope&quot;: &quot;真实曲线控件与 TimelineEditor,标量编辑与文档往返。&quot;,
  1942. &quot;status&quot;: &quot;PASS&quot;,
  1943. &quot;kind&quot;: &quot;unit&quot;,
  1944. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  1945. },
  1946. {
  1947. &quot;title&quot;: &quot;curve vector editing preserves other components and selected track; invalid values do not mutate&quot;,
  1948. &quot;featureIds&quot;: [
  1949. &quot;curve.value&quot;
  1950. ],
  1951. &quot;scope&quot;: &quot;向量其它分量保留,当前轨道、非法值保护;不包含显示轴切换或可视像素验收。&quot;,
  1952. &quot;status&quot;: &quot;PASS&quot;,
  1953. &quot;kind&quot;: &quot;unit&quot;,
  1954. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  1955. },
  1956. {
  1957. &quot;title&quot;: &quot;multiple tracks on one property use last effective value; capture subtracts it only once&quot;,
  1958. &quot;featureIds&quot;: [
  1959. &quot;timeline.multitrack&quot;
  1960. ],
  1961. &quot;scope&quot;: &quot;调用实际 apply/capture/update 基值方法;验证同属性最后有效轨道、静音/删除后中性姿态,偏移只扣一次。&quot;,
  1962. &quot;status&quot;: &quot;PASS&quot;,
  1963. &quot;kind&quot;: &quot;unit&quot;,
  1964. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  1965. },
  1966. {
  1967. &quot;title&quot;: &quot;changing a binding resets the former target and keeps manual transform edits as base&quot;,
  1968. &quot;featureIds&quot;: [
  1969. &quot;timeline.multitrack&quot;,
  1970. &quot;timeline.target&quot;
  1971. ],
  1972. &quot;scope&quot;: &quot;轨道重绑后旧目标复位,手动变换成为新基值;不假称鼠标拖动已验。&quot;,
  1973. &quot;status&quot;: &quot;PASS&quot;,
  1974. &quot;kind&quot;: &quot;unit&quot;,
  1975. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  1976. },
  1977. {
  1978. &quot;title&quot;: &quot;custom properties and extension labels survive actual capture, project JSON and object restore&quot;,
  1979. &quot;featureIds&quot;: [
  1980. &quot;property.code&quot;,
  1981. &quot;property.status&quot;,
  1982. &quot;component.tag&quot;
  1983. ],
  1984. &quot;scope&quot;: &quot;真实对象 capture、normalization、JSON 与 restore 往返;清空和撤销到未存在字段状态。&quot;,
  1985. &quot;status&quot;: &quot;PASS&quot;,
  1986. &quot;kind&quot;: &quot;unit&quot;,
  1987. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  1988. },
  1989. {
  1990. &quot;title&quot;: &quot;boolean, numeric and nested blueprint conditions select their true/false branches&quot;,
  1991. &quot;featureIds&quot;: [
  1992. &quot;blueprint.condition&quot;
  1993. ],
  1994. &quot;scope&quot;: &quot;布尔、数字、truthy 与嵌套路径值解析。&quot;,
  1995. &quot;status&quot;: &quot;PASS&quot;,
  1996. &quot;kind&quot;: &quot;unit&quot;,
  1997. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  1998. },
  1999. {
  2000. &quot;title&quot;: &quot;visible child under a hidden ancestor cannot be picked or highlighted; trigger aliases include ancestors&quot;,
  2001. &quot;featureIds&quot;: [
  2002. &quot;tree.visibility&quot;,
  2003. &quot;blueprint.highlight&quot;
  2004. ],
  2005. &quot;scope&quot;: &quot;共用可见性和祖先别名函数;鼠标事件另由 E2E 验证。&quot;,
  2006. &quot;status&quot;: &quot;PASS&quot;,
  2007. &quot;kind&quot;: &quot;unit&quot;,
  2008. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2009. },
  2010. {
  2011. &quot;title&quot;: &quot;inspector state tags reflect ancestor visibility and actual shadow flags, with a host editability hook&quot;,
  2012. &quot;featureIds&quot;: [
  2013. &quot;property.identity&quot;
  2014. ],
  2015. &quot;scope&quot;: &quot;真实属性 DOM 显示隐藏/阴影状态,并提供宿主权限标签 hook;不伪称此单测完成会话鉴权。&quot;,
  2016. &quot;status&quot;: &quot;PASS&quot;,
  2017. &quot;kind&quot;: &quot;unit&quot;,
  2018. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2019. },
  2020. {
  2021. &quot;title&quot;: &quot;history retains 60 states, truncates redo after edits and ignores duplicate snapshots&quot;,
  2022. &quot;featureIds&quot;: [
  2023. &quot;project.undo&quot;,
  2024. &quot;project.redo&quot;
  2025. ],
  2026. &quot;scope&quot;: &quot;60 个快照上限、重复状态忽略及新编辑截断 redo 分支。&quot;,
  2027. &quot;status&quot;: &quot;PASS&quot;,
  2028. &quot;kind&quot;: &quot;unit&quot;,
  2029. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2030. },
  2031. {
  2032. &quot;title&quot;: &quot;history serializes async restores and leaves index unchanged when restoration fails&quot;,
  2033. &quot;featureIds&quot;: [
  2034. &quot;project.undo&quot;,
  2035. &quot;project.redo&quot;
  2036. ],
  2037. &quot;scope&quot;: &quot;异步互斥、下载失败不移动索引,解除锁后可继续操作。&quot;,
  2038. &quot;status&quot;: &quot;PASS&quot;,
  2039. &quot;kind&quot;: &quot;unit&quot;,
  2040. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2041. },
  2042. {
  2043. &quot;title&quot;: &quot;managed-GLB history downloads the snapshot stable reference before restoring, without rewriting it&quot;,
  2044. &quot;featureIds&quot;: [
  2045. &quot;project.undo&quot;,
  2046. &quot;project.redo&quot;
  2047. ],
  2048. &quot;scope&quot;: &quot;受控 GLB 快照先物化再恢复,不把临时 URL 写回快照。&quot;,
  2049. &quot;status&quot;: &quot;PASS&quot;,
  2050. &quot;kind&quot;: &quot;unit&quot;,
  2051. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2052. },
  2053. {
  2054. &quot;title&quot;: &quot;beforeunload recovery does not create a draft for key order alone, but preserves real unsaved changes&quot;,
  2055. &quot;featureIds&quot;: [
  2056. &quot;project.recovery&quot;
  2057. ],
  2058. &quot;scope&quot;: &quot;同语义对象键顺序不产生假恢复稿;真正修改仍保留。不包含全部恢复/隔离/下载 UI 分支。&quot;,
  2059. &quot;status&quot;: &quot;PASS&quot;,
  2060. &quot;kind&quot;: &quot;unit&quot;,
  2061. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2062. },
  2063. {
  2064. &quot;title&quot;: &quot;highlight rejects missing/hidden targets and transient colors never enter a saved project&quot;,
  2065. &quot;featureIds&quot;: [
  2066. &quot;blueprint.highlight&quot;
  2067. ],
  2068. &quot;scope&quot;: &quot;目标不存在/隐藏报错,执行时暂态发光颜色不进入保存文档,结束恢复原材质。&quot;,
  2069. &quot;status&quot;: &quot;PASS&quot;,
  2070. &quot;kind&quot;: &quot;unit&quot;,
  2071. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2072. },
  2073. {
  2074. &quot;title&quot;: &quot;API publish supplies current cover, blocks duplicate publication and reports preserved old cover once&quot;,
  2075. &quot;featureIds&quot;: [
  2076. &quot;publish.api&quot;,
  2077. &quot;publish.cover&quot;,
  2078. &quot;feedback.toast&quot;
  2079. ],
  2080. &quot;scope&quot;: &quot;实际发布宿主方法传封面、重入阻断和上传失败只提示一次;模拟 API,不是实际服务响应。&quot;,
  2081. &quot;status&quot;: &quot;PASS&quot;,
  2082. &quot;kind&quot;: &quot;unit&quot;,
  2083. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2084. },
  2085. {
  2086. &quot;title&quot;: &quot;API conflict leaves publication failed and releases the cover guard&quot;,
  2087. &quot;featureIds&quot;: [
  2088. &quot;project.conflict&quot;,
  2089. &quot;publish.api&quot;,
  2090. &quot;publish.cover&quot;
  2091. ],
  2092. &quot;scope&quot;: &quot;409 分支不误报已发布并释放 busy 标记;模拟 API。&quot;,
  2093. &quot;status&quot;: &quot;PASS&quot;,
  2094. &quot;kind&quot;: &quot;unit&quot;,
  2095. &quot;testFile&quot;: &quot;unreal_tran/tests/model-main-closure.test.mjs&quot;
  2096. }
  2097. ],
  2098. &quot;runtime&quot;: {
  2099. &quot;authSha256&quot;: &quot;95b8487ca6a1d970387214b027ee9c1d34ae0d1d5c988574c024805d8bb61d9b&quot;,
  2100. &quot;tranSha256&quot;: &quot;e9528d739d6d817ebf7c5b9a34302195156b1543663066f5484c86c594c6e729&quot;,
  2101. &quot;builtEqualsRunning&quot;: true,
  2102. &quot;fileService&quot;: &quot;开发进程撤销旧17180转发覆盖,恢复已配置远端文件服务&quot;
  2103. },
  2104. &quot;previousWorkPushed&quot;: {
  2105. &quot;api&quot;: &quot;71df00dffa39a8f49a4f0654969a3014c2f78f67&quot;,
  2106. &quot;web&quot;: &quot;3f39e2c94df9cdadf3545ae14bf0df41f2c37bf1&quot;,
  2107. &quot;e2e&quot;: &quot;b3d4ce8ffd8144090c18c8a28f5ca824170042c8&quot;
  2108. }
  2109. }</pre></article>
  2110. <article class="panel"><h3>测试数据保留与清理</h3><p><a href="cleanup.json">清理结果</a></p><pre>{
  2111. &quot;time&quot;: &quot;2026-09-06T08:27:13.581Z&quot;,
  2112. &quot;status&quot;: &quot;PASS&quot;,
  2113. &quot;originals&quot;: [
  2114. {
  2115. &quot;id&quot;: &quot;157&quot;,
  2116. &quot;name&quot;: &quot;实测模型-狐狸动画-已验证-20260905&quot;,
  2117. &quot;version&quot;: 15,
  2118. &quot;unchanged&quot;: true
  2119. },
  2120. {
  2121. &quot;id&quot;: &quot;156&quot;,
  2122. &quot;name&quot;: &quot;实测模型-牛奶卡车-已验证-20260905&quot;,
  2123. &quot;version&quot;: 20,
  2124. &quot;unchanged&quot;: true
  2125. },
  2126. {
  2127. &quot;id&quot;: &quot;94&quot;,
  2128. &quot;name&quot;: &quot;桥梁架设装备整机模型&quot;,
  2129. &quot;version&quot;: 253,
  2130. &quot;unchanged&quot;: true
  2131. }
  2132. ],
  2133. &quot;projects&quot;: [
  2134. {
  2135. &quot;id&quot;: &quot;168&quot;,
  2136. &quot;alreadyAbsent&quot;: true
  2137. },
  2138. {
  2139. &quot;id&quot;: &quot;169&quot;,
  2140. &quot;alreadyAbsent&quot;: true
  2141. },
  2142. {
  2143. &quot;id&quot;: &quot;170&quot;,
  2144. &quot;alreadyAbsent&quot;: true
  2145. },
  2146. {
  2147. &quot;id&quot;: &quot;171&quot;,
  2148. &quot;alreadyAbsent&quot;: true
  2149. },
  2150. {
  2151. &quot;id&quot;: &quot;172&quot;,
  2152. &quot;alreadyAbsent&quot;: true
  2153. },
  2154. {
  2155. &quot;id&quot;: &quot;173&quot;,
  2156. &quot;alreadyAbsent&quot;: true
  2157. },
  2158. {
  2159. &quot;id&quot;: &quot;174&quot;,
  2160. &quot;alreadyAbsent&quot;: true
  2161. },
  2162. {
  2163. &quot;id&quot;: &quot;175&quot;,
  2164. &quot;alreadyAbsent&quot;: true
  2165. },
  2166. {
  2167. &quot;id&quot;: &quot;176&quot;,
  2168. &quot;alreadyAbsent&quot;: true
  2169. },
  2170. {
  2171. &quot;id&quot;: &quot;177&quot;,
  2172. &quot;alreadyAbsent&quot;: true
  2173. },
  2174. {
  2175. &quot;id&quot;: &quot;178&quot;,
  2176. &quot;alreadyAbsent&quot;: true
  2177. },
  2178. {
  2179. &quot;id&quot;: &quot;179&quot;,
  2180. &quot;alreadyAbsent&quot;: true
  2181. },
  2182. {
  2183. &quot;id&quot;: &quot;180&quot;,
  2184. &quot;alreadyAbsent&quot;: true
  2185. },
  2186. {
  2187. &quot;id&quot;: &quot;181&quot;,
  2188. &quot;alreadyAbsent&quot;: true
  2189. },
  2190. {
  2191. &quot;id&quot;: &quot;182&quot;,
  2192. &quot;alreadyAbsent&quot;: true
  2193. },
  2194. {
  2195. &quot;id&quot;: &quot;183&quot;,
  2196. &quot;name&quot;: &quot;闭环导航名称-183&quot;,
  2197. &quot;withdrawn&quot;: false,
  2198. &quot;removed&quot;: true
  2199. },
  2200. {
  2201. &quot;id&quot;: &quot;184&quot;,
  2202. &quot;name&quot;: &quot;闭环验收-资源往返-mtph19ll&quot;,
  2203. &quot;withdrawn&quot;: false,
  2204. &quot;removed&quot;: true
  2205. },
  2206. {
  2207. &quot;id&quot;: &quot;185&quot;,
  2208. &quot;name&quot;: &quot;闭环验收-三维手柄-1788678747289&quot;,
  2209. &quot;withdrawn&quot;: false,
  2210. &quot;removed&quot;: true
  2211. },
  2212. {
  2213. &quot;id&quot;: &quot;186&quot;,
  2214. &quot;name&quot;: &quot;闭环验收-离开保护-1788678780620&quot;,
  2215. &quot;withdrawn&quot;: false,
  2216. &quot;removed&quot;: true
  2217. },
  2218. {
  2219. &quot;id&quot;: &quot;187&quot;,
  2220. &quot;name&quot;: &quot;闭环验收-恢复副本-mtph6hw8&quot;,
  2221. &quot;withdrawn&quot;: false,
  2222. &quot;removed&quot;: true
  2223. },
  2224. {
  2225. &quot;id&quot;: &quot;188&quot;,
  2226. &quot;name&quot;: &quot;闭环验收-加载与预检-mtph6ubj&quot;,
  2227. &quot;withdrawn&quot;: false,
  2228. &quot;removed&quot;: true
  2229. },
  2230. {
  2231. &quot;id&quot;: &quot;189&quot;,
  2232. &quot;name&quot;: &quot;闭环验收-三维手柄-1788678838243&quot;,
  2233. &quot;withdrawn&quot;: false,
  2234. &quot;removed&quot;: true
  2235. },
  2236. {
  2237. &quot;id&quot;: &quot;190&quot;,
  2238. &quot;name&quot;: &quot;闭环验收-离开保护-1788678850196&quot;,
  2239. &quot;withdrawn&quot;: false,
  2240. &quot;removed&quot;: true
  2241. },
  2242. {
  2243. &quot;id&quot;: &quot;191&quot;,
  2244. &quot;name&quot;: &quot;闭环工具补充-卡车控件-mtpha049&quot;,
  2245. &quot;withdrawn&quot;: false,
  2246. &quot;removed&quot;: true
  2247. },
  2248. {
  2249. &quot;id&quot;: &quot;192&quot;,
  2250. &quot;name&quot;: &quot;闭环工具补充-卡车控件-mtphbg8t&quot;,
  2251. &quot;withdrawn&quot;: false,
  2252. &quot;removed&quot;: true
  2253. },
  2254. {
  2255. &quot;id&quot;: &quot;193&quot;,
  2256. &quot;name&quot;: &quot;闭环工具补充-基准匹配-mtphbpqq&quot;,
  2257. &quot;withdrawn&quot;: false,
  2258. &quot;removed&quot;: true
  2259. },
  2260. {
  2261. &quot;id&quot;: &quot;194&quot;,
  2262. &quot;name&quot;: &quot;闭环工具补充-卡车控件-mtphfk1m&quot;,
  2263. &quot;withdrawn&quot;: false,
  2264. &quot;removed&quot;: true
  2265. },
  2266. {
  2267. &quot;id&quot;: &quot;195&quot;,
  2268. &quot;name&quot;: &quot;闭环工具补充-基准匹配-mtphfu32&quot;,
  2269. &quot;withdrawn&quot;: false,
  2270. &quot;removed&quot;: true
  2271. },
  2272. {
  2273. &quot;id&quot;: &quot;196&quot;,
  2274. &quot;name&quot;: &quot;闭环验收-资源往返-mtphjhoi&quot;,
  2275. &quot;withdrawn&quot;: false,
  2276. &quot;removed&quot;: true
  2277. },
  2278. {
  2279. &quot;id&quot;: &quot;197&quot;,
  2280. &quot;name&quot;: &quot;闭环验收-拒绝非法资源-mtphjv5x&quot;,
  2281. &quot;withdrawn&quot;: false,
  2282. &quot;removed&quot;: true
  2283. },
  2284. {
  2285. &quot;id&quot;: &quot;198&quot;,
  2286. &quot;name&quot;: &quot;闭环验收-保存失败恢复-mtphk0kk&quot;,
  2287. &quot;withdrawn&quot;: false,
  2288. &quot;removed&quot;: true
  2289. },
  2290. {
  2291. &quot;id&quot;: &quot;199&quot;,
  2292. &quot;name&quot;: &quot;闭环验收-发布封面版本-mtphk960&quot;,
  2293. &quot;withdrawn&quot;: true,
  2294. &quot;removed&quot;: true
  2295. },
  2296. {
  2297. &quot;id&quot;: &quot;200&quot;,
  2298. &quot;name&quot;: &quot;闭环工具补充-卡车控件-mtphkrbz&quot;,
  2299. &quot;withdrawn&quot;: false,
  2300. &quot;removed&quot;: true
  2301. },
  2302. {
  2303. &quot;id&quot;: &quot;201&quot;,
  2304. &quot;name&quot;: &quot;闭环工具补充-基准匹配-mtphkzlj&quot;,
  2305. &quot;withdrawn&quot;: false,
  2306. &quot;removed&quot;: true
  2307. },
  2308. {
  2309. &quot;id&quot;: &quot;202&quot;,
  2310. &quot;name&quot;: &quot;闭环新建-1788679561949&quot;,
  2311. &quot;withdrawn&quot;: false,
  2312. &quot;removed&quot;: true
  2313. },
  2314. {
  2315. &quot;id&quot;: &quot;203&quot;,
  2316. &quot;name&quot;: &quot;闭环验收-三维手柄-1788679613072&quot;,
  2317. &quot;withdrawn&quot;: false,
  2318. &quot;removed&quot;: true
  2319. },
  2320. {
  2321. &quot;id&quot;: &quot;204&quot;,
  2322. &quot;name&quot;: &quot;闭环验收-离开保护-1788679623529&quot;,
  2323. &quot;withdrawn&quot;: false,
  2324. &quot;removed&quot;: true
  2325. },
  2326. {
  2327. &quot;id&quot;: &quot;205&quot;,
  2328. &quot;name&quot;: &quot;闭环补充-资源库-mtphobxb&quot;,
  2329. &quot;withdrawn&quot;: false,
  2330. &quot;removed&quot;: true
  2331. },
  2332. {
  2333. &quot;id&quot;: &quot;206&quot;,
  2334. &quot;name&quot;: &quot;闭环补充-内置环境-mtphomov&quot;,
  2335. &quot;withdrawn&quot;: false,
  2336. &quot;removed&quot;: true
  2337. },
  2338. {
  2339. &quot;id&quot;: &quot;207&quot;,
  2340. &quot;name&quot;: &quot;闭环导航名称-207&quot;,
  2341. &quot;withdrawn&quot;: false,
  2342. &quot;removed&quot;: true
  2343. },
  2344. {
  2345. &quot;id&quot;: &quot;208&quot;,
  2346. &quot;name&quot;: &quot;闭环验收-恢复副本-mtphpz7v&quot;,
  2347. &quot;withdrawn&quot;: false,
  2348. &quot;removed&quot;: true
  2349. },
  2350. {
  2351. &quot;id&quot;: &quot;209&quot;,
  2352. &quot;name&quot;: &quot;闭环验收-加载与预检-mtphq9y1&quot;,
  2353. &quot;withdrawn&quot;: false,
  2354. &quot;removed&quot;: true
  2355. },
  2356. {
  2357. &quot;id&quot;: &quot;210&quot;,
  2358. &quot;name&quot;: &quot;闭环验收-离开保护-1788681347476&quot;,
  2359. &quot;withdrawn&quot;: false,
  2360. &quot;removed&quot;: true
  2361. },
  2362. {
  2363. &quot;id&quot;: &quot;211&quot;,
  2364. &quot;name&quot;: &quot;闭环补充-内置环境-mtpip60q&quot;,
  2365. &quot;withdrawn&quot;: false,
  2366. &quot;removed&quot;: true
  2367. },
  2368. {
  2369. &quot;id&quot;: &quot;212&quot;,
  2370. &quot;name&quot;: &quot;闭环验收-资源往返-mtpjbnl2&quot;,
  2371. &quot;withdrawn&quot;: false,
  2372. &quot;removed&quot;: true
  2373. },
  2374. {
  2375. &quot;id&quot;: &quot;213&quot;,
  2376. &quot;name&quot;: &quot;闭环验收-拒绝非法资源-mtpjbyqo&quot;,
  2377. &quot;withdrawn&quot;: false,
  2378. &quot;removed&quot;: true
  2379. },
  2380. {
  2381. &quot;id&quot;: &quot;214&quot;,
  2382. &quot;name&quot;: &quot;闭环验收-保存失败恢复-mtpjc2vu&quot;,
  2383. &quot;withdrawn&quot;: false,
  2384. &quot;removed&quot;: true
  2385. },
  2386. {
  2387. &quot;id&quot;: &quot;215&quot;,
  2388. &quot;name&quot;: &quot;闭环验收-发布封面版本-mtpjcafv&quot;,
  2389. &quot;withdrawn&quot;: true,
  2390. &quot;removed&quot;: true
  2391. },
  2392. {
  2393. &quot;id&quot;: &quot;216&quot;,
  2394. &quot;name&quot;: &quot;闭环工具补充-卡车控件-mtpjcof8&quot;,
  2395. &quot;withdrawn&quot;: false,
  2396. &quot;removed&quot;: true
  2397. },
  2398. {
  2399. &quot;id&quot;: &quot;217&quot;,
  2400. &quot;name&quot;: &quot;闭环工具补充-基准匹配-mtpjcvxe&quot;,
  2401. &quot;withdrawn&quot;: false,
  2402. &quot;removed&quot;: true
  2403. },
  2404. {
  2405. &quot;id&quot;: &quot;218&quot;,
  2406. &quot;name&quot;: &quot;闭环新建-1788682528069&quot;,
  2407. &quot;withdrawn&quot;: false,
  2408. &quot;removed&quot;: true
  2409. },
  2410. {
  2411. &quot;id&quot;: &quot;219&quot;,
  2412. &quot;name&quot;: &quot;闭环验收-三维手柄-1788682536810&quot;,
  2413. &quot;withdrawn&quot;: false,
  2414. &quot;removed&quot;: true
  2415. },
  2416. {
  2417. &quot;id&quot;: &quot;220&quot;,
  2418. &quot;name&quot;: &quot;闭环验收-离开保护-1788682545004&quot;,
  2419. &quot;withdrawn&quot;: false,
  2420. &quot;removed&quot;: true
  2421. },
  2422. {
  2423. &quot;id&quot;: &quot;221&quot;,
  2424. &quot;name&quot;: &quot;闭环补充-资源库-mtpjesgj&quot;,
  2425. &quot;withdrawn&quot;: false,
  2426. &quot;removed&quot;: true
  2427. },
  2428. {
  2429. &quot;id&quot;: &quot;222&quot;,
  2430. &quot;name&quot;: &quot;闭环补充-内置环境-mtpjezfi&quot;,
  2431. &quot;withdrawn&quot;: false,
  2432. &quot;removed&quot;: true
  2433. },
  2434. {
  2435. &quot;id&quot;: &quot;223&quot;,
  2436. &quot;name&quot;: &quot;闭环导航名称-223&quot;,
  2437. &quot;withdrawn&quot;: false,
  2438. &quot;removed&quot;: true
  2439. },
  2440. {
  2441. &quot;id&quot;: &quot;224&quot;,
  2442. &quot;name&quot;: &quot;闭环验收-恢复副本-mtpjg6y2&quot;,
  2443. &quot;withdrawn&quot;: false,
  2444. &quot;removed&quot;: true
  2445. },
  2446. {
  2447. &quot;id&quot;: &quot;225&quot;,
  2448. &quot;name&quot;: &quot;闭环验收-加载与预检-mtpjgfnd&quot;,
  2449. &quot;withdrawn&quot;: false,
  2450. &quot;removed&quot;: true
  2451. },
  2452. {
  2453. &quot;id&quot;: &quot;226&quot;,
  2454. &quot;name&quot;: &quot;闭环验收-资源往返-mtpjkcpq&quot;,
  2455. &quot;withdrawn&quot;: false,
  2456. &quot;removed&quot;: true
  2457. },
  2458. {
  2459. &quot;id&quot;: &quot;227&quot;,
  2460. &quot;name&quot;: &quot;闭环验收-拒绝非法资源-mtpjko7g&quot;,
  2461. &quot;withdrawn&quot;: false,
  2462. &quot;removed&quot;: true
  2463. },
  2464. {
  2465. &quot;id&quot;: &quot;228&quot;,
  2466. &quot;name&quot;: &quot;闭环验收-保存失败恢复-mtpjkshn&quot;,
  2467. &quot;withdrawn&quot;: false,
  2468. &quot;removed&quot;: true
  2469. },
  2470. {
  2471. &quot;id&quot;: &quot;229&quot;,
  2472. &quot;name&quot;: &quot;闭环验收-发布封面版本-mtpjkzt1&quot;,
  2473. &quot;withdrawn&quot;: true,
  2474. &quot;removed&quot;: true
  2475. },
  2476. {
  2477. &quot;id&quot;: &quot;230&quot;,
  2478. &quot;name&quot;: &quot;闭环工具补充-卡车控件-mtpjlf69&quot;,
  2479. &quot;withdrawn&quot;: false,
  2480. &quot;removed&quot;: true
  2481. },
  2482. {
  2483. &quot;id&quot;: &quot;231&quot;,
  2484. &quot;name&quot;: &quot;闭环工具补充-基准匹配-mtpjlmiy&quot;,
  2485. &quot;withdrawn&quot;: false,
  2486. &quot;removed&quot;: true
  2487. },
  2488. {
  2489. &quot;id&quot;: &quot;232&quot;,
  2490. &quot;name&quot;: &quot;闭环新建-1788682938712&quot;,
  2491. &quot;withdrawn&quot;: false,
  2492. &quot;removed&quot;: true
  2493. },
  2494. {
  2495. &quot;id&quot;: &quot;233&quot;,
  2496. &quot;name&quot;: &quot;闭环验收-三维手柄-1788682951454&quot;,
  2497. &quot;withdrawn&quot;: false,
  2498. &quot;removed&quot;: true
  2499. },
  2500. {
  2501. &quot;id&quot;: &quot;234&quot;,
  2502. &quot;name&quot;: &quot;闭环验收-离开保护-1788682960426&quot;,
  2503. &quot;withdrawn&quot;: false,
  2504. &quot;removed&quot;: true
  2505. },
  2506. {
  2507. &quot;id&quot;: &quot;235&quot;,
  2508. &quot;name&quot;: &quot;闭环补充-资源库-mtpjnoh9&quot;,
  2509. &quot;withdrawn&quot;: false,
  2510. &quot;removed&quot;: true
  2511. },
  2512. {
  2513. &quot;id&quot;: &quot;236&quot;,
  2514. &quot;name&quot;: &quot;闭环补充-内置环境-mtpjnv0t&quot;,
  2515. &quot;withdrawn&quot;: false,
  2516. &quot;removed&quot;: true
  2517. },
  2518. {
  2519. &quot;id&quot;: &quot;237&quot;,
  2520. &quot;name&quot;: &quot;闭环导航名称-237&quot;,
  2521. &quot;withdrawn&quot;: false,
  2522. &quot;removed&quot;: true
  2523. },
  2524. {
  2525. &quot;id&quot;: &quot;238&quot;,
  2526. &quot;name&quot;: &quot;闭环验收-恢复副本-mtpjp3nr&quot;,
  2527. &quot;withdrawn&quot;: false,
  2528. &quot;removed&quot;: true
  2529. },
  2530. {
  2531. &quot;id&quot;: &quot;239&quot;,
  2532. &quot;name&quot;: &quot;闭环验收-加载与预检-mtpjpdaj&quot;,
  2533. &quot;withdrawn&quot;: false,
  2534. &quot;removed&quot;: true
  2535. }
  2536. ]
  2537. }</pre></article>
  2538. <article class="panel"><h3>交付物凭据与附件检查</h3><p><span class="badge pass">最终扫描通过</span> · <a href="artifact-checks.json">脱敏扫描结果</a></p><p>四个仓库相对 HEAD 的变动/新增文件与本轮完整报告;真实本地账号密码精确匹配、可解码 JWT、ZIP/Playwright 内嵌报告逐项解压扫描及 PNG 文本元数据。输出不包含任何命中值或附近正文。</p><p class="muted">扫描 104 份文本、122 张图片的文本元数据及 1 个归档;图片正文不以文本扫描代替视觉 QA。</p><details><summary>检查范围、历史常量排除与限制</summary><pre>{
  2539. &quot;time&quot;: &quot;2026-09-06T08:33:57.163137+00:00&quot;,
  2540. &quot;status&quot;: &quot;PASS&quot;,
  2541. &quot;secretScan&quot;: &quot;PASS&quot;,
  2542. &quot;phase&quot;: &quot;final&quot;,
  2543. &quot;finalArtifactScan&quot;: true,
  2544. &quot;scope&quot;: &quot;四个仓库相对 HEAD 的变动/新增文件与本轮完整报告;真实本地账号密码精确匹配、可解码 JWT、ZIP/Playwright 内嵌报告逐项解压扫描及 PNG 文本元数据。输出不包含任何命中值或附近正文。&quot;,
  2545. &quot;baselinePolicy&quot;: &quot;只排除 HEAD 已存在且邻近至少64字符完全一致的普通源码/固定库字符串(统一CRLF/LF);新哈希模型bundle另允许至少25个邻近词元在仅归一化压缩变量名后完全一致,且命中须为更长固定常量的子串、不能是完整密码值。唯一经本轮复核的配置例外是 ut_auth/src/main/resources/application.yml 的 bootstrap-admin-password 环境变量默认项:文件、键、整行须与 HEAD 完全相同,且新旧文件各只出现一次;改值、改变量名、复制到其他文件或新增同一行均仍失败。其他真实凭据赋值与ZIP内元数据不作排除。Playwright静态库对比HEAD上一轮报告壳。&quot;,
  2546. &quot;limitations&quot;: [
  2547. &quot;图片仅扫描可读元数据,不执行OCR;图像正文由浏览器报告视觉QA核对。&quot;,
  2548. &quot;只扫描本轮交付范围,不声称已审计整个历史仓库。&quot;,
  2549. &quot;初查通过不代表最终结果文件已完成,最终需 --final 再执行。&quot;
  2550. ],
  2551. &quot;selfChecks&quot;: {
  2552. &quot;status&quot;: &quot;PASS&quot;,
  2553. &quot;tests&quot;: 15
  2554. },
  2555. &quot;repositoryHeads&quot;: {
  2556. &quot;unreal_tran&quot;: &quot;d16184acf1686bb4a6ad44949d0587c5373ffbde&quot;,
  2557. &quot;unreal_tran_web&quot;: &quot;3f39e2c94df9cdadf3545ae14bf0df41f2c37bf1&quot;,
  2558. &quot;unreal_tran_api&quot;: &quot;71df00dffa39a8f49a4f0654969a3014c2f78f67&quot;,
  2559. &quot;ute2e&quot;: &quot;b3d4ce8ffd8144090c18c8a28f5ca824170042c8&quot;
  2560. },
  2561. &quot;changedFileCounts&quot;: {
  2562. &quot;unreal_tran&quot;: 14,
  2563. &quot;unreal_tran_web&quot;: 8,
  2564. &quot;unreal_tran_api&quot;: 15,
  2565. &quot;ute2e&quot;: 184
  2566. },
  2567. &quot;deletedFileCounts&quot;: {
  2568. &quot;unreal_tran&quot;: 0,
  2569. &quot;unreal_tran_web&quot;: 2,
  2570. &quot;unreal_tran_api&quot;: 0,
  2571. &quot;ute2e&quot;: 0
  2572. },
  2573. &quot;textArtifactsScanned&quot;: 104,
  2574. &quot;pngMetadataFilesScanned&quot;: 122,
  2575. &quot;archives&quot;: [
  2576. {
  2577. &quot;file&quot;: &quot;ute2e/reports/model-editor-closure-20260906/playwright/index.html!embedded-report-1.zip&quot;,
  2578. &quot;entries&quot;: 7,
  2579. &quot;textEntries&quot;: 7
  2580. }
  2581. ],
  2582. &quot;finalInputs&quot;: {
  2583. &quot;results.json&quot;: true,
  2584. &quot;validation.json&quot;: true,
  2585. &quot;cleanup.json&quot;: true,
  2586. &quot;playwright/index.html&quot;: true
  2587. },
  2588. &quot;finalInputSha256&quot;: {
  2589. &quot;results.json&quot;: &quot;f37013658c8c38a5ec5993e636a30ad57eee9d3bcc119650c929952de8d556e9&quot;,
  2590. &quot;validation.json&quot;: &quot;6e0e87d0df73061bc8549d3405f03731fecf077d7425f52eeed45008f7d09959&quot;,
  2591. &quot;cleanup.json&quot;: &quot;ab2776afa143d9937651daa8fa18b531a3fb84c703f5f5b0918930e78c76eb26&quot;,
  2592. &quot;playwright/index.html&quot;: &quot;92dcca3fe570530bde973b9e09199c064fc2b343bb6f8a21b67fb3c72b8949ed&quot;
  2593. },
  2594. &quot;unchangedBaselineExclusions&quot;: [
  2595. {
  2596. &quot;file&quot;: &quot;unreal_tran_api/ut_auth/src/main/resources/application.yml&quot;,
  2597. &quot;baseline&quot;: &quot;unreal_tran_api/HEAD:ut_auth/src/main/resources/application.yml&quot;,
  2598. &quot;occurrences&quot;: 1
  2599. },
  2600. {
  2601. &quot;file&quot;: &quot;unreal_tran_api/wiki/11-内容制作模块.md&quot;,
  2602. &quot;baseline&quot;: &quot;unreal_tran_api/HEAD:wiki/11-内容制作模块.md&quot;,
  2603. &quot;occurrences&quot;: 17
  2604. },
  2605. {
  2606. &quot;file&quot;: &quot;unreal_tran_web/public/legacy-model-editor/assets/editor-BAqfQ3VC.js&quot;,
  2607. &quot;baseline&quot;: &quot;unreal_tran_web/HEAD:public/legacy-model-editor/assets/editor-CunHwJSa.js&quot;,
  2608. &quot;occurrences&quot;: 1
  2609. },
  2610. {
  2611. &quot;file&quot;: &quot;ute2e/reports/model-editor-closure-20260906/playwright/index.html&quot;,
  2612. &quot;baseline&quot;: &quot;ute2e/HEAD:reports/role-permissions-20260906/playwright/index.html&quot;,
  2613. &quot;occurrences&quot;: 1
  2614. }
  2615. ],
  2616. &quot;unscannedBinaryFiles&quot;: [],
  2617. &quot;findings&quot;: []
  2618. }</pre></details></article></section>
  2619. <section id="decisions"><div class="section-label">需要产品确认 / 3 项</div><h2>较大调整的具体范围</h2><p>以下能力超出现有小范围修复。本轮保留入口并明确现状;确认范围后才能据此另行实现和验收。</p><article class="panel decision"><span class="decision-id">D1</span><h3>真正的组件运行系统</h3><dl><dt>当前行为</dt><dd>“组件”页目前是内置能力说明;新增项只保存扩展标记名称,没有启停、参数执行或生命周期。</dd><dt>拟实现的可观察行为</dt><dd>用户新增一种行为组件,配置参数后能在当前模型和约定下游环境执行;停用后立即停止,重开后按保存状态恢复。</dd><dt>建议确认的实施范围</dt><dd>先定义有限组件目录、参数 schema、权限与版本;实现初始化/更新/销毁及错误隔离。不要直接开放任意脚本。</dd><dt>验收条件</dt><dd>每种批准组件可添加、编辑、启停、删除、保存重开;重复载入不重复绑定事件;失败组件不阻断其他对象,运行结果可定位。</dd></dl></article><article class="panel decision"><span class="decision-id">D2</span><h3>完整三维离线运行包</h3><dl><dt>当前行为</dt><dd>现有 HTML 是嵌入静态截图与工程数据的步骤演示,可离线查看;没有 GLB 字节和完整三维运行时。</dd><dt>拟实现的可观察行为</dt><dd>断网电脑打开交付包,真实模型/材质/原生动画/编辑时间轴与交互节点可以运行,且不依赖服务端 blob URL。</dd><dt>建议确认的实施范围</dt><dd>明确交付形式(目录/ZIP或单文件)、体积约束、资产授权和三维依赖;打包全部受控资产、运行时和相对资源清单。</dd><dt>验收条件</dt><dd>清缓存断网运行;模型和环境完整可见,动作/分支/高亮可交互;资源缺失明确报错;包内清单/哈希与发布版本一致。</dd></dl></article><article class="panel decision"><span class="decision-id">D3</span><h3>下游场景 / 训练自动执行模型动画与蓝图</h3><dl><dt>当前行为</dt><dd>发布模型可供下游按固定版本引用;不同下游已有局部动画能力,但没有统一的模型 timeline/blueprint 自动执行桥接。加载成功不等于动作已自动执行。</dd><dt>拟实现的可观察行为</dt><dd>在场景或训练放入模型实例后,按明确触发策略启动该发布版本的时间轴/蓝图;多个实例互不干扰。</dd><dt>建议确认的实施范围</dt><dd>统一实例目标命名空间、事件总线、生命周期和停止规则;明确自动播放、用户触发与训练步骤触发优先级,以及错误/完成结果回传。</dd><dt>验收条件</dt><dd>两个同模型实例分别触发不串台;锁定发布版本;停止/切步骤/卸载无迟到动作;真实对象姿态、分支和结果回传均有 E2E 证据。</dd></dl></article></section>
  2620. <section id="screenshots"><div class="section-label">可视证据</div><h2>41 张截图 · 点击放大</h2><p class="muted">截图来自实际目录;首次加载、过程画面和最终结果按图注说明,不把空场景或加载遮罩当作模型可见证据。</p><div class="gallery"><figure><a class="shot" href="screenshots/01-components-saved.png" data-caption="对象属性与扩展标记保存"><img src="screenshots/01-components-saved.png" loading="lazy" alt="对象属性与扩展标记保存"></a><figcaption><span class="shot-number">01</span><strong>对象属性与扩展标记保存</strong><span class="badge pass">本轮附件一致</span><p>通过真实属性控件编辑并保存;新增内容是可持久化的名称标记,不代表组件运行行为已经实现。</p><small>01-components-saved.png</small></figcaption></figure><figure><a class="shot" href="screenshots/02-properties-reopened.png" data-caption="刷新后的模型属性"><img src="screenshots/02-properties-reopened.png" loading="lazy" alt="刷新后的模型属性"></a><figcaption><span class="shot-number">02</span><strong>刷新后的模型属性</strong><span class="badge pass">本轮附件一致</span><p>重新加载服务端工程后核对对象名称、变换、首个材质槽、自定义字段和扩展标记;不是仅核对保存提示。</p><small>02-properties-reopened.png</small></figcaption></figure><figure><a class="shot" href="screenshots/03-fox-preview.png" data-caption="狐狸模型运行预览"><img src="screenshots/03-fox-preview.png" loading="lazy" alt="狐狸模型运行预览"></a><figcaption><span class="shot-number">03</span><strong>狐狸模型运行预览</strong><span class="badge pass">本轮附件一致</span><p>真实狐狸模型在编辑器预览视口显示。临时网格、线框、透视等视图选项与模型数据保存分开验收。</p><small>03-fox-preview.png</small></figcaption></figure><figure><a class="shot" href="screenshots/04-new-retry-dialog.png" data-caption="新建失败后的重试界面"><img src="screenshots/04-new-retry-dialog.png" loading="lazy" alt="新建失败后的重试界面"></a><figcaption><span class="shot-number">04</span><strong>新建失败后的重试界面</strong><span class="badge pass">本轮附件一致</span><p>定向注入创建请求失败,核对原工程保留及新建表单可重试;该画面不表示开发服务自然发生故障。</p><small>04-new-retry-dialog.png</small></figcaption></figure><figure><a class="shot" href="screenshots/05-new-separate-project.png" data-caption="新建独立模型工程"><img src="screenshots/05-new-separate-project.png" loading="lazy" alt="新建独立模型工程"></a><figcaption><span class="shot-number">05</span><strong>新建独立模型工程</strong><span class="badge pass">本轮附件一致</span><p>新建走真实创建接口并进入新项目 ID,原模型工程没有被清空覆盖。</p><small>05-new-separate-project.png</small></figcaption></figure><figure><a class="shot" href="screenshots/06-readonly-permissions.png" data-caption="只读模型入口"><img src="screenshots/06-readonly-permissions.png" loading="lazy" alt="只读模型入口"></a><figcaption><span class="shot-number">06</span><strong>只读模型入口</strong><span class="badge pass">本轮附件一致</span><p>使用本轮实际权限会话检查只读控件及接口拒绝;平台角色名称本身不授予内容写权限。</p><small>06-readonly-permissions.png</small></figcaption></figure><figure><a class="shot" href="screenshots/21-truck-timeline-controls.png" data-caption="卡车时间轴与部件轨道"><img src="screenshots/21-truck-timeline-controls.png" loading="lazy" alt="卡车时间轴与部件轨道"></a><figcaption><span class="shot-number">07</span><strong>卡车时间轴与部件轨道</strong><span class="badge pass">本轮附件一致</span><p>真实轨道增删、目标绑定、播放停止、静音和关键帧操作。当前截图停在零秒;它不表示原生 GLB 动画已经变成多条可编辑时间轴。</p><small>21-truck-timeline-controls.png</small></figcaption></figure><figure><a class="shot" href="screenshots/22-truck-curve-value-five.png" data-caption="曲线编辑:部件 X=5 的测试姿态"><img src="screenshots/22-truck-curve-value-five.png" loading="lazy" alt="曲线编辑:部件 X=5 的测试姿态"></a><figcaption><span class="shot-number">08</span><strong>曲线编辑:部件 X=5 的测试姿态</strong><span class="badge pass">本轮附件一致</span><p>将卡车车身部件关键帧 X 改为 5 验证曲线与真实视口联动,因此车身与轮子暂时分离;这是测试姿态,不是模型加载丢失。</p><small>22-truck-curve-value-five.png</small></figcaption></figure><figure><a class="shot" href="screenshots/23-truck-blueprint-seven-nodes.png" data-caption="七种蓝图节点与真实端口连线"><img src="screenshots/23-truck-blueprint-seven-nodes.png" loading="lazy" alt="七种蓝图节点与真实端口连线"></a><figcaption><span class="shot-number">09</span><strong>七种蓝图节点与真实端口连线</strong><span class="badge pass">本轮附件一致</span><p>节点通过节点库创建,参数使用实际控件编辑,端口通过指针拖线连接;蓝图图数据随后保存重开核对。</p><small>23-truck-blueprint-seven-nodes.png</small></figcaption></figure><figure><a class="shot" href="screenshots/24-truck-blueprint-real-message.png" data-caption="蓝图执行到操作提示"><img src="screenshots/24-truck-blueprint-real-message.png" loading="lazy" alt="蓝图执行到操作提示"></a><figcaption><span class="shot-number">10</span><strong>蓝图执行到操作提示</strong><span class="badge pass">本轮附件一致</span><p>编辑器真实 handler 驱动时间轴、等待、高亮与提示节点;不是替换 handler 的演示截图。</p><small>24-truck-blueprint-real-message.png</small></figcaption></figure><figure><a class="shot" href="screenshots/25-truck-blueprint-completed-log.png" data-caption="蓝图完成与本次运行日志"><img src="screenshots/25-truck-blueprint-completed-log.png" loading="lazy" alt="蓝图完成与本次运行日志"></a><figcaption><span class="shot-number">11</span><strong>蓝图完成与本次运行日志</strong><span class="badge pass">本轮附件一致</span><p>用例检查节点顺序、条件出口和完成事件;右侧日志只记录当前运行,不等同服务端审计或教学成绩。</p><small>25-truck-blueprint-completed-log.png</small></figcaption></figure><figure><a class="shot" href="screenshots/26-truck-condition-branches-runtime.png" data-caption="条件真假出口的运行时补充检查"><img src="screenshots/26-truck-condition-branches-runtime.png" loading="lazy" alt="条件真假出口的运行时补充检查"></a><figcaption><span class="shot-number">12</span><strong>条件真假出口的运行时补充检查</strong><span class="badge pass">本轮附件一致</span><p>对已由 UI 创建的图调用运行时接口检查 true/false 与不匹配目标;这张图标记为运行时证据,不能当成纯鼠标 UI 覆盖。</p><small>26-truck-condition-branches-runtime.png</small></figcaption></figure><figure><a class="shot" href="screenshots/27-truck-preview-auto.png" data-caption="进入预览自动触发蓝图"><img src="screenshots/27-truck-preview-auto.png" loading="lazy" alt="进入预览自动触发蓝图"></a><figcaption><span class="shot-number">13</span><strong>进入预览自动触发蓝图</strong><span class="badge pass">本轮附件一致</span><p>真实点击进入预览后派发 auto,校验只启动一次;不代表下游场景或训练会自动运行模型蓝图。</p><small>27-truck-preview-auto.png</small></figcaption></figure><figure><a class="shot" href="screenshots/27-truck-preview-click.png" data-caption="真实单击卡车触发蓝图"><img src="screenshots/27-truck-preview-click.png" loading="lazy" alt="真实单击卡车触发蓝图"></a><figcaption><span class="shot-number">14</span><strong>真实单击卡车触发蓝图</strong><span class="badge pass">本轮附件一致</span><p>在真实可见网格像素上单击,校验只启动一次且流程完成;没有伪造 trigger 事件。</p><small>27-truck-preview-click.png</small></figcaption></figure><figure><a class="shot" href="screenshots/27-truck-preview-double-click.png" data-caption="真实双击卡车触发蓝图"><img src="screenshots/27-truck-preview-double-click.png" loading="lazy" alt="真实双击卡车触发蓝图"></a><figcaption><span class="shot-number">15</span><strong>真实双击卡车触发蓝图</strong><span class="badge pass">本轮附件一致</span><p>通过 renderer canvas 双击命中真实模型,校验事件匹配与单次执行;避免单击误启动双击/自动触发器。</p><small>27-truck-preview-double-click.png</small></figcaption></figure><figure><a class="shot" href="screenshots/28-curve-axis-y-negative.png" data-caption="曲线分量切换与负值"><img src="screenshots/28-curve-axis-y-negative.png" loading="lazy" alt="曲线分量切换与负值"></a><figcaption><span class="shot-number">16</span><strong>曲线分量切换与负值</strong><span class="badge pass">本轮附件一致</span><p>在独立卡车副本中设置关键帧 X=5、Y=-2,切换曲线显示分量并比较曲线路径,确认切换视图不修改关键帧数据。车身偏移是特意设置的测试姿态。</p><small>28-curve-axis-y-negative.png</small></figcaption></figure><figure><a class="shot" href="screenshots/29-timeline-seek-record.png" data-caption="真实刻度定位、方向键与关键帧记录"><img src="screenshots/29-timeline-seek-record.png" loading="lazy" alt="真实刻度定位、方向键与关键帧记录"></a><figcaption><span class="shot-number">17</span><strong>真实刻度定位、方向键与关键帧记录</strong><span class="badge pass">本轮附件一致</span><p>通过时间刻度点击/拖动、左右与 Shift 按键定位时间,再用实际关键帧按钮记录当前偏移,核对时间码、关键帧和持久化内容。</p><small>29-timeline-seek-record.png</small></figcaption></figure><figure><a class="shot" href="screenshots/30-assets-environment-reopened.png" data-caption="主狐狸与外部方盒环境同时重开"><img src="screenshots/30-assets-environment-reopened.png" loading="lazy" alt="主狐狸与外部方盒环境同时重开"></a><figcaption><span class="shot-number">18</span><strong>主狐狸与外部方盒环境同时重开</strong><span class="badge pass">本轮附件一致</span><p>狐狸是主模型,旁边方盒是轻量环境 GLB;两者使用独立受控资产引用,刷新后均有真实网格。当前镜头较远,资产身份以随附 API 断言核对。</p><small>30-assets-environment-reopened.png</small></figcaption></figure><figure><a class="shot" href="screenshots/30-blueprint-palette-canvas.png" data-caption="蓝图库搜索、真实拖入与画布操作"><img src="screenshots/30-blueprint-palette-canvas.png" loading="lazy" alt="蓝图库搜索、真实拖入与画布操作"></a><figcaption><span class="shot-number">19</span><strong>蓝图库搜索、真实拖入与画布操作</strong><span class="badge pass">本轮附件一致</span><p>搜索并清空节点库,通过 HTML5 拖放添加节点,核对工具栏默认添加、画布滚轮缩放/平移/适应操作没有意外改变节点图。</p><small>30-blueprint-palette-canvas.png</small></figcaption></figure><figure><a class="shot" href="screenshots/31-bridge-baseline-reopened.png" data-caption="匹配模型的基准时间轴保存重开"><img src="screenshots/31-bridge-baseline-reopened.png" loading="lazy" alt="匹配模型的基准时间轴保存重开"></a><figcaption><span class="shot-number">20</span><strong>匹配模型的基准时间轴保存重开</strong><span class="badge pass">本轮附件一致</span><p>在独立匹配装备副本载入基准动作,核对轨道目标存在、项目名称保留、保存刷新后时间轴一致;不匹配卡车分支另外验证原时间轴未被覆盖。仅验证通用编辑数据,不制作实际维修流程。</p><small>31-bridge-baseline-reopened.png</small></figcaption></figure><figure><a class="shot" href="screenshots/31-invalid-import-keeps-model.png" data-caption="无效工程导入保留原模型"><img src="screenshots/31-invalid-import-keeps-model.png" loading="lazy" alt="无效工程导入保留原模型"></a><figcaption><span class="shot-number">21</span><strong>无效工程导入保留原模型</strong><span class="badge pass">本轮附件一致</span><p>非法 JSON 或无有效受控引用的导入被拒绝;核对原模型与工程内容仍在,没有以默认模型静默替换。</p><small>31-invalid-import-keeps-model.png</small></figcaption></figure><figure><a class="shot" href="screenshots/32-save-conflict-keeps-recovery.png" data-caption="版本冲突阻断保存并保留恢复稿"><img src="screenshots/32-save-conflict-keeps-recovery.png" loading="lazy" alt="版本冲突阻断保存并保留恢复稿"></a><figcaption><span class="shot-number">22</span><strong>版本冲突阻断保存并保留恢复稿</strong><span class="badge pass">本轮附件一致</span><p>通过定向注入 409 验证保存失败分支及恢复数据,不将失败提示本身当成成功保存。</p><small>32-save-conflict-keeps-recovery.png</small></figcaption></figure><figure><a class="shot" href="screenshots/33-save-retry-success.png" data-caption="保存失败后再次保存成功"><img src="screenshots/33-save-retry-success.png" loading="lazy" alt="保存失败后再次保存成功"></a><figcaption><span class="shot-number">23</span><strong>保存失败后再次保存成功</strong><span class="badge pass">本轮附件一致</span><p>恢复正常请求后点击真实保存。右上红色 409 提示来自上一故障注入步骤,截图时尚在自动消退周期内;本次重试成功由当前 PUT 响应和保存后的刷新断言确认。失败后的旧上传票据不得被误复用。</p><small>33-save-retry-success.png</small></figcaption></figure><figure><a class="shot" href="screenshots/34-published-current-cover.png" data-caption="发布版本与当前视口封面"><img src="screenshots/34-published-current-cover.png" loading="lazy" alt="发布版本与当前视口封面"></a><figcaption><span class="shot-number">24</span><strong>发布版本与当前视口封面</strong><span class="badge pass">本轮附件一致</span><p>发布接口、保存版本和受控封面资产一起核对;封面来自当前三维视口。下载后的下游资源验证不等于下游自动执行蓝图。</p><small>34-published-current-cover.png</small></figcaption></figure><figure><a class="shot" href="screenshots/35-offline-step-demo-actual-file.png" data-caption="实际下载的步骤演示 HTML"><img src="screenshots/35-offline-step-demo-actual-file.png" loading="lazy" alt="实际下载的步骤演示 HTML"></a><figcaption><span class="shot-number">25</span><strong>实际下载的步骤演示 HTML</strong><span class="badge pass">本轮附件一致</span><p>打开真实导出文件检查步骤演示内容。此文件不含完整三维模型和资源,完整三维离线包列为待确认范围。</p><small>35-offline-step-demo-actual-file.png</small></figcaption></figure><figure><a class="shot" href="screenshots/41-resource-search-restored.png" data-caption="资源搜索清空后恢复卡片"><img src="screenshots/41-resource-search-restored.png" loading="lazy" alt="资源搜索清空后恢复卡片"></a><figcaption><span class="shot-number">26</span><strong>资源搜索清空后恢复卡片</strong><span class="badge pass">本轮附件一致</span><p>输入命中关键字、无匹配关键字,再清空搜索,断言卡片数量与空结果状态;仅搜索当前目录。</p><small>41-resource-search-restored.png</small></figcaption></figure><figure><a class="shot" href="screenshots/42-resource-card-switch-reopened.png" data-caption="真实资源卡片切换后刷新"><img src="screenshots/42-resource-card-switch-reopened.png" loading="lazy" alt="真实资源卡片切换后刷新"></a><figcaption><span class="shot-number">27</span><strong>真实资源卡片切换后刷新</strong><span class="badge pass">本轮附件一致</span><p>在独立副本导入小方盒,再点回原狐狸卡片;保存刷新后核对原资产 ID、code 与真实网格,不改原模型数据。</p><small>42-resource-card-switch-reopened.png</small></figcaption></figure><figure><a class="shot" href="screenshots/43-builtin-workshop-reopened.png" data-caption="内置车间环境保存重开"><img src="screenshots/43-builtin-workshop-reopened.png" loading="lazy" alt="内置车间环境保存重开"></a><figcaption><span class="shot-number">28</span><strong>内置车间环境保存重开</strong><span class="badge pass">本轮附件一致</span><p>真实切换内置车间、保存和刷新后核对环境类型与网格;树计数、折叠和展开同时验证。</p><small>43-builtin-workshop-reopened.png</small></figcaption></figure><figure><a class="shot" href="screenshots/44-builtin-outdoor-reopened.png" data-caption="内置野外环境保存重开"><img src="screenshots/44-builtin-outdoor-reopened.png" loading="lazy" alt="内置野外环境保存重开"></a><figcaption><span class="shot-number">29</span><strong>内置野外环境保存重开</strong><span class="badge pass">本轮附件一致</span><p>真实切换内置野外、保存和刷新后核对环境类型与网格;程序化环境不冒称外部 GLB。</p><small>44-builtin-outdoor-reopened.png</small></figcaption></figure><figure><a class="shot" href="screenshots/45-builtin-depot-reopened.png" data-caption="内置装备车库保存重开"><img src="screenshots/45-builtin-depot-reopened.png" loading="lazy" alt="内置装备车库保存重开"></a><figcaption><span class="shot-number">30</span><strong>内置装备车库保存重开</strong><span class="badge pass">本轮附件一致</span><p>真实加载随包车库 GLB,保存刷新后检查 builtin-gltf 来源与网格;树总数与当前展开行数分开统计。</p><small>45-builtin-depot-reopened.png</small></figcaption></figure><figure><a class="shot" href="screenshots/46-preview-navigation.png" data-caption="预览前后步与退出"><img src="screenshots/46-preview-navigation.png" loading="lazy" alt="预览前后步与退出"></a><figcaption><span class="shot-number">31</span><strong>预览前后步与退出</strong><span class="badge pass">本轮附件一致</span><p>通过真实按钮验证下一步推进两秒、上一步回零,并用 Escape 返回编辑;预览步进不是创建新的业务步骤。</p><small>46-preview-navigation.png</small></figcaption></figure><figure><a class="shot" href="screenshots/47-navigation-autosave-log.png" data-caption="等待自动保存后刷新核对字段"><img src="screenshots/47-navigation-autosave-log.png" loading="lazy" alt="等待自动保存后刷新核对字段"></a><figcaption><span class="shot-number">32</span><strong>等待自动保存后刷新核对字段</strong><span class="badge pass">本轮附件一致</span><p>自定义编码修改后没有点击保存,等待实际 30 秒自动 PUT;刷新确认名称与编码保留。下方日志为本次加载运行日志,FPS 与显存只作状态展示。</p><small>47-navigation-autosave-log.png</small></figcaption></figure><figure><a class="shot" href="screenshots/51-transform-gizmos.png" data-caption="真实手柄操作的旋转与单轴缩放测试姿态"><img src="screenshots/51-transform-gizmos.png" loading="lazy" alt="真实手柄操作的旋转与单轴缩放测试姿态"></a><figcaption><span class="shot-number">33</span><strong>真实手柄操作的旋转与单轴缩放测试姿态</strong><span class="badge pass">本轮附件一致</span><p>为了验证真实平移、旋转与缩放手柄,特意把狐狸旋转至侧立并缩小 X 轴;画面中的侧立和压扁属于测试姿态,不是加载变形。定位只读投影,没有脚本写姿态;随后撤销/重做、保存刷新核对。</p><small>51-transform-gizmos.png</small></figcaption></figure><figure><a class="shot" href="screenshots/52-leave-save-failure.png" data-caption="未保存离开遇到保存失败"><img src="screenshots/52-leave-save-failure.png" loading="lazy" alt="未保存离开遇到保存失败"></a><figcaption><span class="shot-number">34</span><strong>未保存离开遇到保存失败</strong><span class="badge pass">本轮附件一致</span><p>关闭确认框保留修改;定向注入保存 503 后仍留在原页,解除异常后重试保存才离开,最终 API 核对数据。</p><small>52-leave-save-failure.png</small></figcaption></figure><figure><a class="shot" href="screenshots/60-same-version-real-recovery.png" data-caption="真实未保存修改触发同版本恢复"><img src="screenshots/60-same-version-real-recovery.png" loading="lazy" alt="真实未保存修改触发同版本恢复"></a><figcaption><span class="shot-number">35</span><strong>真实未保存修改触发同版本恢复</strong><span class="badge pass">本轮附件一致</span><p>先在实际属性控件修改,再刷新触发 beforeunload 恢复稿;没有预先注入 localStorage 假快照。此时服务端版本未变化。</p><small>60-same-version-real-recovery.png</small></figcaption></figure><figure><a class="shot" href="screenshots/61-recovered-draft-explicitly-saved.png" data-caption="恢复稿经显式保存后落库"><img src="screenshots/61-recovered-draft-explicitly-saved.png" loading="lazy" alt="恢复稿经显式保存后落库"></a><figcaption><span class="shot-number">36</span><strong>恢复稿经显式保存后落库</strong><span class="badge pass">本轮附件一致</span><p>点击恢复后编辑器保留需显式保存状态;实际点击保存才更新服务端版本,恢复名称与原受控模型一致。</p><small>61-recovered-draft-explicitly-saved.png</small></figcaption></figure><figure><a class="shot" href="screenshots/62-stale-version-recovery-protection.png" data-caption="旧版本恢复稿只下载与隔离"><img src="screenshots/62-stale-version-recovery-protection.png" loading="lazy" alt="旧版本恢复稿只下载与隔离"></a><figcaption><span class="shot-number">37</span><strong>旧版本恢复稿只下载与隔离</strong><span class="badge pass">本轮附件一致</span><p>在独立副本模拟另一个编辑器保存;旧稿不显示覆盖恢复按钮,只下载并隔离保留,服务端较新内容未被覆盖。</p><small>62-stale-version-recovery-protection.png</small></figcaption></figure><figure><a class="shot" href="screenshots/63-controlled-glb-download-failed.png" data-caption="受控模型下载失败时禁止编辑"><img src="screenshots/63-controlled-glb-download-failed.png" loading="lazy" alt="受控模型下载失败时禁止编辑"></a><figcaption><span class="shot-number">38</span><strong>受控模型下载失败时禁止编辑</strong><span class="badge pass">本轮附件一致</span><p>定向注入资源下载 503,中性加载失败界面保留重试入口,保存与发布均禁用;空白视口不作为模型加载成功。</p><small>63-controlled-glb-download-failed.png</small></figcaption></figure><figure><a class="shot" href="screenshots/64-controlled-glb-retry-loaded.png" data-caption="解除资源故障后实际重试成功"><img src="screenshots/64-controlled-glb-retry-loaded.png" loading="lazy" alt="解除资源故障后实际重试成功"></a><figcaption><span class="shot-number">39</span><strong>解除资源故障后实际重试成功</strong><span class="badge pass">本轮附件一致</span><p>解除下载故障后点击宿主重试,iframe 重新载入并出现真实模型网格;没有以默认占位模型绕过失败。</p><small>64-controlled-glb-retry-loaded.png</small></figcaption></figure><figure><a class="shot" href="screenshots/65-publish-preflight-readonly.png" data-caption="发布预检清单与只读开关行为"><img src="screenshots/65-publish-preflight-readonly.png" loading="lazy" alt="发布预检清单与只读开关行为"></a><figcaption><span class="shot-number">40</span><strong>发布预检清单与只读开关行为</strong><span class="badge pass">本轮附件一致</span><p>打开和关闭预检面板不会写入项目;错误受控资产引用的 JSON 在替换模型前被拒绝。面板绿标不能替代服务端发布校验。</p><small>65-publish-preflight-readonly.png</small></figcaption></figure><figure><a class="shot" href="screenshots/66-depot-saved-return-list.png" data-caption="车库保存后正常返回列表"><img src="screenshots/66-depot-saved-return-list.png" loading="lazy" alt="车库保存后正常返回列表"></a><figcaption><span class="shot-number">41</span><strong>车库保存后正常返回列表</strong><span class="badge pass">本轮附件一致</span><p>车库环境保存后使用正式宿主导航返回列表,确认不会因旧版规范化器把 depot 误改成 outdoor 而产生虚假的未保存提示;实际修改仍受离开保护。</p><small>66-depot-saved-return-list.png</small></figcaption></figure></div></section>
  2621. <section><div class="section-label">交付文件</div><h2>证据与复现入口</h2><div class="panel links"><a href="results.json">results.json</a><a href="run-history.json">run-history.json</a><a href="validation.json">validation.json</a><a href="cleanup.json">cleanup.json</a><a href="artifact-checks.json">artifact-checks.json</a><a href="coverage.json">coverage.json</a><a href="feature-catalog.json">feature-catalog.json</a><a href="coverage-plan.md">coverage-plan.md</a><a href="data/inventory-main.md">data/inventory-main.md</a><a href="data/unit-coverage-plan.json">data/unit-coverage-plan.json</a><a href="data/final-corrections.json">data/final-corrections.json</a><a href="data/kingbase-validation-probe-result.json">data/kingbase-validation-probe-result.json</a><a href="data/visual-qa.json">data/visual-qa.json</a><a href="screenshot-captions.json">screenshot-captions.json</a><a href="screenshot-verification.json">screenshot-verification.json</a><a href="evidence/30-assets-roundtrip.json">evidence/30-assets-roundtrip.json</a><a href="evidence/31-invalid-import.json">evidence/31-invalid-import.json</a><a href="evidence/32-save-failure-recovery.json">evidence/32-save-failure-recovery.json</a><a href="evidence/34-publish-fixed-version.json">evidence/34-publish-fixed-version.json</a><a href="evidence/41-resource-search-switch.json">evidence/41-resource-search-switch.json</a><a href="evidence/43-builtin-environments-tree.json">evidence/43-builtin-environments-tree.json</a><a href="evidence/46-navigation-panels-autosave.json">evidence/46-navigation-panels-autosave.json</a><a href="evidence/51-gizmos.json">evidence/51-gizmos.json</a><a href="evidence/52-leave.json">evidence/52-leave.json</a><a href="evidence/60-project-recovery.json">evidence/60-project-recovery.json</a><a href="evidence/63-loading-publish-preflight.json">evidence/63-loading-publish-preflight.json</a><a href="evidence/new-project.json">evidence/new-project.json</a><a href="evidence/permissions.json">evidence/permissions.json</a><a href="evidence/properties.json">evidence/properties.json</a><a href="evidence/truck-blueprint-events.json">evidence/truck-blueprint-events.json</a><a href="evidence/truck-blueprint-tool-supplement.json">evidence/truck-blueprint-tool-supplement.json</a><a href="evidence/truck-blueprint-ui.json">evidence/truck-blueprint-ui.json</a><a href="evidence/truck-timeline-curve.json">evidence/truck-timeline-curve.json</a><a href="evidence/viewport.json">evidence/viewport.json</a></div></section><footer>生成命令:<code>node tools/build-model-editor-closure-report.mjs</code>。功能实现状态与验证状态独立;缺失、失败或未确认的最终轮结果绝不自动改为 PASS。报告不读取私有账号文件、会话配置或数据库备份。</footer></main>
  2622. <dialog id="image-viewer" aria-label="截图放大"><div class="dialog-bar"><span id="image-title"></span><div><a id="image-original" target="_blank" rel="noopener">原图</a> <button id="image-close" type="button">关闭 ×</button></div></div><img alt=""></dialog><script>
  2623. const query=document.getElementById('feature-search'), filter=document.getElementById('feature-state');function applyFilter(){let count=0;const search=query.value.toLowerCase();document.querySelectorAll('[data-feature-state]').forEach(row=>{const visible=(filter.value==='all'||row.dataset.featureState===filter.value)&&row.textContent.toLowerCase().includes(search);row.classList.toggle('hidden',!visible);if(visible)count++});document.querySelectorAll('[data-group]').forEach(group=>group.classList.toggle('hidden',!group.querySelector('[data-feature-state]:not(.hidden)')));document.getElementById('feature-visible').textContent=count+' 项'}query.addEventListener('input',applyFilter);filter.addEventListener('change',applyFilter);const viewer=document.getElementById('image-viewer'),large=viewer.querySelector('img');document.querySelectorAll('a.shot').forEach(link=>link.addEventListener('click',event=>{event.preventDefault();large.src=link.href;large.alt=link.dataset.caption;document.getElementById('image-title').textContent=link.dataset.caption;document.getElementById('image-original').href=link.href;viewer.showModal()}));document.getElementById('image-close').addEventListener('click',()=>viewer.close());viewer.addEventListener('click',event=>{if(event.target===viewer)viewer.close()});
  2624. </script></body></html>