BossAgents SCSAI 回写优化 — 编码任务规划文档

BossAgents SCSAI 回写优化 — 编码任务规划文档

版本:v2.0 | 日期:2026-06-26 | 基于 spec-SCSAI回写优化.md v2.0 + design-SCSAI回写优化.md v1.0


项目约束提醒

  • 包管理:项目基于 pnpm,不涉及包管理变更
  • server.js:POST 路由需先 collectBody(req) 获取 bodyStr,新增路由需遵守此约定
  • 导出方式module.exports = CapabilityDispatcher(直接导出类),不修改
  • 前端构建:前端修改后需 npm run build
  • 进程管理:不要用 Stop-Process -Name "node"
  • 前端权威:前端 AmlBuilder.js 是唯一真相源,后端 aml-builder.js 是其镜像;前端 useCapabilityCreate.js 是创建权威实现,前端创建不走后端业务逻辑层
  • 关键模块行号
  • rule-engine.js(2708行):executeGenerate() 第1683行,createItem() 第2480行附近
  • capability-runtime.js(1334行):generate() 第774行,create() 第839行
  • aml-generator.js(544行):_buildAML() 第347行,_buildRelationshipsXml() 第385行
  • aras-client.js(583行):_sendRequest() 第88行,_parseFault() 第137行
  • relationship-resolver.js(726行):discoverRelations() 第247行
  • aml-builder.js(225行):buildItemElement() 第43行,buildRelationshipElement() 第99行
  • useCapabilityCreate.js(2008行):10步完整创建流程

P0 优先级任务(核心缺陷,必须完成)


TASK-P0-01: generate 输出标准化(rule-engine.js)

  • 对应需求:P0-5.1(spec §5.1)
  • 优先级:P0
  • 依赖任务:无
  • 预估工作量:1天

#### 实现步骤

步骤1:在 rule-engine.js 中新增 _standardizeGeneratedContent() 方法

  • 文件:server/core/rule-engine.js
  • 位置:在 executeGenerate() 方法之后添加
  • 操作:新增 _standardizeGeneratedContent(rawContent, item_type) 方法,处理以下情况:
  1. 已是标准格式(含 item_type + properties)→ 直接返回
  2. 字符串 → 尝试 JSON 解析(正则提取 {...} 块),解析失败 → 包装为 { item_type, properties: { description: rawContent }, _unparseable: true }
  3. 解析后有 properties 字段但无 item_type → 注入 item_type,补齐 item_propertiesrelationships
  4. 扁平属性对象 → 提取 relationships/item_properties,其余归入 properties
  5. 无法解析 → 包装为 { item_type, properties: { description: String(rawContent) }, _unparseable: true }
  • 参考代码:design §1.3.1 第158-208行

步骤2:修改 executeGenerate() 返回值,使用标准化 generated_content

  • 文件:server/core/rule-engine.js
  • 位置:第1714-1731行,executeGenerate() 返回值构建处
  • 操作:
  1. 在第1718行 generatedContent = best.result?.generated_content || best.result?.transformed_content || null; 之后,调用 generatedContent = this._standardizeGeneratedContent(generatedContent, item_type)
  2. 返回值中的 generated_content 使用标准化后的结果
  • 参考代码:design §1.3.1 第158-208行

步骤3:确认 executeGenerate() 不自行调用 createItem()

  • 文件:server/core/rule-engine.js
  • 操作:审计 executeGenerate() 代码路径(第1683-1731行),确认不包含对 createItem()applyAML() 的直接调用
  • 验收:代码审计通过,executeGenerate() 中无 createItem/applyAML 调用

#### 验证方法

  1. 启动服务 node server.js,确认无启动报错
  2. 调用 POST /api/capability,body 为 { "capability": "generate", "params": { "item_type": "Part", "data": { "name": "测试零件" } } }
  3. 验证返回结果 generated_content 包含 { item_type: 'Part', properties: {...}, item_properties: {}, relationships: [] } 标准格式
  4. 测试 LLM 降级路径:传入未知类型,验证 LLM 返回也被标准化

TASK-P0-02: generate 输出标准化(capability-runtime.js + 前端对接)

  • 对应需求:P0-5.1(spec §5.1)
  • 优先级:P0
  • 依赖任务:TASK-P0-01(rule-engine.js 标准化方法先实现)
  • 预估工作量:1.5天

#### 实现步骤

步骤1:在 capability-runtime.js 的 generate() 方法中确保输出格式标准化

  • 文件:server/core/capability-runtime.js
  • 位置:第774行 generate() 方法
  • 操作:
  1. 在第781-784行规则引擎命中分支中,对 result.generated_content 调用 _standardizeGeneratedContent() 标准化
  2. 在第788-797行 LLM 降级分支中,对 llmResult.data || llmResult.raw 调用 _standardizeGeneratedContent() 标准化
  3. 新增 _standardizeGeneratedContent(rawContent, item_type) 方法(逻辑与 rule-engine.js 中一致)
  4. 在返回结果中添加 autoCreate 标记:result.autoCreate = context.autoCreate !== false(默认 true)
  • 参考代码:design §1.3.1 第216-310行

步骤2:在前端 useCapabilityCreate.js 中新增 createFromGenerate() 方法

  • 文件:src/composables/useCapabilityCreate.js
  • 位置:在现有 createObject() 方法之后添加
  • 操作:
  1. 新增 async function createFromGenerate(generatedContent, options = {}) 方法
  2. 格式校验:检查 generatedContent.item_type 是否存在,不存在则设置 error.value = '生成内容无法自动创建,请手动填写'
  3. 保留生成内容:result.value = { generated_content: generatedContent }(确保创建失败不丢失)
  4. autoCreate 控制:options.autoCreate === false 时仅展示,不自动创建
  5. 自动创建:调用 createObject({ item_type, properties, item_properties, relationships }) 复用现有10步流程
  6. 创建失败时保留 generatedContent,设置 error.value = '创建失败: ${e.message},生成内容已保留'
  • 参考代码:design §1.3.1 第318-361行

步骤3:前端 generate 能力调用后自动衔接创建流程

  • 文件:src/composables/useCapabilityCreate.js(或调用 generate 能力的组件)
  • 操作:
  1. 在前端调用 generate 能力后,检查返回结果的 generated_contentautoCreate 标记
  2. autoCreate !== false 时,自动调用 createFromGenerate(generatedContent)
  3. generated_content._unparseable === true 时,展示原始文本,提示"生成内容无法自动创建,请手动填写"

#### 验证方法

  1. 调用 POST /api/capability,body 为 { "capability": "generate", "params": { "item_type": "Part", "data": { "name": "测试零件" }, "autoCreate": true } }
  2. 验证返回结果包含 autoCreate: true 和标准格式 generated_content
  3. 前端测试:调用 generate 后验证自动启动创建流程
  4. 测试 autoCreate: false,验证仅展示不自动创建
  5. 测试 generate 失败场景,验证生成内容不丢失

TASK-P0-03: AMLGenerator 降级路径 item_properties 补齐

  • 对应需求:P0-5.2(spec §5.2)
  • 优先级:P0
  • 依赖任务:无
  • 预估工作量:1.5天

#### 实现步骤

步骤1:修改 aml-generator.js 的 _buildAML() 方法,添加 item_properties 支持

  • 文件:server/core/aml-generator.js
  • 位置:第347行 _buildAML(data, schema, options) 方法
  • 操作:
  1. 在第352行 skipKeys 数组中添加 'item_properties''_item_properties'
  2. 在属性 XML 构建的 .filter() 中添加排除条件:key !== 'item_properties' && key !== '_item_properties'
  3. 在属性 XML 构建的 .map() 中添加 item/foreign 类型对象值检测:
  • dataType === 'item' || dataType === 'foreign'typeof value === 'object' → 转入 itemProps[key] = value,返回 null
  • dataType === 'item' || dataType === 'foreign' 且值为字符串(GUID)→ 直接输出
  1. .filter(Boolean) 后添加过滤掉 null(被转入 item_properties 的字段)
  2. data.item_properties || data._item_properties || {} 收集 item_properties
  3. 在属性 XML 之后、relationships XML 之前,调用 _buildItemPropertiesXml(itemProps) 生成嵌套 XML
  4. itemPropsXml 拼接到 propertiesXml 之后
  • 参考代码:design §1.3.2 第424-480行

步骤2:新增 _buildItemPropertiesXml() 方法

  • 文件:server/core/aml-generator.js
  • 位置:在 _buildAML() 方法之后、_buildRelationshipsXml() 方法之前添加
  • 操作:新增 _buildItemPropertiesXml(itemProperties) 方法,与 aml-builder.jsbuildItemElement() 第60-76行逻辑一致:
  1. 遍历 itemProperties 对象
  2. action === 'add' 且有 item_type → 嵌套创建:输出 子属性
  • 子属性遍历 propDef.properties,非对象值直接输出
  • 不支持更深层嵌套(超过3层记录 WARNING 日志)
  1. action === 'get' 且有 iditem_type → 引用已有:输出
  2. 所有文本值通过 this._escapeXml() 转义
  3. 无 item_properties 或为空对象时返回空字符串
  • 参考代码:design §1.3.2 第490-525行,同时对照 server/utils/aml-builder.js 第60-76行

步骤3:确认 _escapeXml() 方法可用

  • 文件:server/core/aml-generator.js
  • 操作:确认 _escapeXml() 方法已存在(第534行)且可被 _buildItemPropertiesXml() 调用

#### 验证方法

  1. 构造包含 item_properties 的测试数据:
   const data = {
     name: '测试项目',
     item_properties: {
       wbs_id: { action: 'add', item_type: 'WBS Element', properties: { name: '测试 WBS' } }
     }
   };
   const schema = { itemType: 'Project', properties: {} };
   const aml = amlGenerator._buildAML(data, schema, { action: 'add' });
   
  1. 验证输出 AML 包含 测试 WBS 嵌套结构
  2. 测试 action: 'get' 引用格式:验证输出
  3. 测试 schema 中 item/foreign 类型字段自动识别:wbs_id 类型为 item 且值为对象 → 自动按 item_properties 嵌套输出
  4. 对比 aml-builder.jsbuildItemElement() 对同一数据的输出,验证 item_properties 部分完全一致
  5. 测试无 item_properties 的数据,验证向后兼容,AML 与修改前一致

TASK-P0-04: 关系发现格式转换

  • 对应需求:P0-5.3(spec §5.3)
  • 优先级:P0
  • 依赖任务:无
  • 预估工作量:1天

#### 实现步骤

步骤1:在 relationship-resolver.js 中新增 convertDiscoveryRelations() 静态方法

  • 文件:server/core/relationship-resolver.js
  • 位置:在 discoverRelations() 方法之后添加
  • 操作:新增 static convertDiscoveryRelations(discoveredRelations, batchItems, mainItemType) 方法:
  1. 入参校验:discoveredRelationsbatchItems 非数组或为空 → 返回 []
  2. relation_type 分组:遍历 discoveredRelations,提取 rel.relation_type || rel.relationship_type
  3. relation_type 为空 → 跳过,记录 WARNING 日志 "关系类型为空,跳过"
  4. 索引解析:parentIdx = rel.parent_index ?? rel.source_indexchildIdx = rel.child_index ?? rel.target_index
  5. 索引越界检查:parentIdx < 0 || parentIdx >= batchItems.length → 跳过,记录 WARNING 日志 "关系索引越界"
  6. 提取 related_item_typebatchItems[childIdx].item_type || mainItemType(缺少 item_type 时使用主类型降级,记录 WARNING)
  7. 构建 relatedItem{ properties: { ...batchItems[childIdx] } },附加关系级别属性
  8. 校验转换结果:relationship_type 非空字符串且 related_items 非空数组,不通过则跳过
  9. 返回 AmlBuilder 标准格式数组
  • 参考代码:design §1.3.3 第560-635行

步骤2:修改 capability-runtime.js 的 create() 方法,集成格式转换

  • 文件:server/core/capability-runtime.js
  • 位置:第871-893行,关系发现结果处理处
  • 操作:
  1. 在第880-888行,将当前直接 push source_index/target_index 格式的逻辑替换为格式转换
  2. 导入 RelationshipResolverconst { RelationshipResolver } = require('./relationship-resolver');(如尚未导入)
  3. 调用 RelationshipResolver.convertDiscoveryRelations(discoveredRelations, context.batch_items, item_type) 转换
  4. 将转换后的标准格式关系 push 到 relationships 数组
  5. 保留 try-catch 非阻塞逻辑,格式转换失败时记录 WARNING 日志,跳过该关系
  • 参考代码:design §1.3.3 第642-667行

步骤3:确认传入 AmlBuilder 的 relationships 不含 source_index/target_index

  • 文件:server/core/capability-runtime.js
  • 操作:审计 create() 方法中从关系发现到 AML 构建的代码路径,确认传入 createItem()relationships 数组中不含 source_index/target_index 字段

#### 验证方法

  1. 构造测试数据:
   const discovered = [
     { parent_index: 0, child_index: 1, relation_type: 'Part BOM', properties: { quantity: 2 } }
   ];
   const batchItems = [
     { item_type: 'Part', item_number: 'P-001', name: '父零件' },
     { item_type: 'Part', item_number: 'P-002', name: '子零件' }
   ];
   const result = RelationshipResolver.convertDiscoveryRelations(discovered, batchItems, 'Part');
   
  1. 验证输出为 [{ relationship_type: 'Part BOM', related_item_type: 'Part', related_items: [...] }]
  2. 测试索引越界:parent_index: 99 → 跳过该关系,返回空数组
  3. 测试 relation_type 为空 → 跳过,返回空数组
  4. 端到端测试:通过 POST /api/capability 调用 create,传入 batch_items,验证关系数据正确传入 AML 构建

P1 优先级任务(重要改进,应尽快完成)


TASK-P1-01: aras-client.js 超时与错误结构化

  • 对应需求:P1-5.4(spec §5.4,aras-client.js 部分)
  • 优先级:P1
  • 依赖任务:无
  • 预估工作量:0.5天

#### 实现步骤

步骤1:修改 aras-client.js 的 _sendRequest() 超时处理

  • 文件:server/utils/aras-client.js
  • 位置:第120-124行,req.setTimeout() 回调
  • 操作:
  1. 将超时处理从 reject(new Error('请求超时 (${this.timeout}ms)')) 改为 resolve({ statusCode: 0, headers: {}, data: '', timeoutError: true, timeoutMs: this.timeout })
  2. 这样 sendAML() 可以统一处理超时响应,而非调用方 try-catch
  • 参考代码:design §1.3.4 第704-723行

步骤2:修改 aras-client.js 的 sendAML() 处理超时和 HTTP 错误

  • 文件:server/utils/aras-client.js
  • 位置:sendAML() 方法中 _sendRequest() 调用之后
  • 操作:
  1. 添加超时响应处理:response.timeoutError → 返回 { success: false, items: [], fault: { code: 'TIMEOUT', string: 'SCSAI请求超时 (Xms)', detail: 'timeout after Xms' }, rawXml: '', count: 0 }
  2. 添加 HTTP 错误处理:statusCode >= 400 → 返回 { success: false, items: [], fault: { code: 'HTTP_ERROR', string: 'HTTP XXX', detail: response.data }, rawXml: response.data, count: 0 }
  3. 正常响应继续调用 _parseResponse(response.data)
  • 参考代码:design §1.3.4 第729-767行

步骤3:确认 _parseFault() 方法可用且被 sendAML() 统一使用

  • 文件:server/utils/aras-client.js
  • 操作:确认 _parseFault() 方法(第137行)已存在且被 _parseResponse() 正确调用,SOAP Fault 解析路径统一

#### 验证方法

  1. 测试 aras-client.js 超时:模拟超时场景,验证返回 { success: false, fault: { code: 'TIMEOUT' } } 而非抛异常
  2. 测试 HTTP 错误:模拟 500 响应,验证返回 { success: false, fault: { code: 'HTTP_ERROR' } }
  3. 测试正常 SOAP Fault:模拟 SCSAI 返回 Fault 响应,验证 _parseFault() 正确解析 faultcode/faultstring/detail

TASK-P1-02: 后端创建路径重试机制

  • 对应需求:P1-5.4(spec §5.4,重试部分)
  • 优先级:P1
  • 依赖任务:TASK-P0-03(AMLGenerator item_properties 补齐后,分步降级才能正确构建 AML)、TASK-P1-01(aras-client.js 超时结构化后,重试逻辑才能正确判断错误类型)
  • 预估工作量:1.5天

#### 实现步骤

步骤1:在 rule-engine.js 中新增 _applyAMLWithRetry() 方法

  • 文件:server/core/rule-engine.js
  • 位置:在 createItem() 方法之前添加
  • 操作:新增 async _applyAMLWithRetry(applyAML, aml, context) 方法:
  1. 最大重试次数 maxRetries = 3,循环 attempt = 0..maxRetries
  2. 每次调用 applyAML(currentAml),成功(result.items?.length > 0 || result.Item)→ 返回 { result, retryCount: attempt, retryReasons }
  3. 解析错误 fault = result?.fault || {}faultCode = fault.code || ''faultString = fault.string || ''
  4. 权限错误(/no default permission|permission_id|access denied/i)→ 注入 World 权限重试1次
  5. 唯一性冲突(/not unique|PropertiesAreNotUnique/i)→ item_number 追加后缀 -1/-2/-3,最多3次
  6. 超时(faultCode === 'TIMEOUT')→ 重试1次
  7. 其他错误 → 指数退避重试(1s、2s、4s)
  8. 全部重试失败 → 返回 { result, retryCount, retryReasons, finalFault: fault }
  • 参考代码:design §1.3.4 第782-851行

步骤2:修改 rule-engine.js 的 createItem() 集成重试

  • 文件:server/core/rule-engine.js
  • 位置:第2538-2550行,applyAML 调用处
  • 操作:
  1. const result = await applyAML(aml) 替换为 const { result: applyResult, retryCount, finalFault } = await this._applyAMLWithRetry(applyAML, aml, context)
  2. applyResult 中提取 itemId(保持现有稳健提取逻辑)
  3. itemId 为空时,检查是否有嵌套数据且重试过 → 调用 _stepDownCreate() 分步降级
  4. 分步降级成功 → itemId = stepDownResult.item_id
  5. 分步降级失败 → 返回 { success: false, errors: ['SCSAI提交失败(含分步降级)'], retry_count: retryCount, final_fault: finalFault }
  • 参考代码:design §1.3.4 第895-942行

步骤3:新增 _stepDownCreate() 方法(分步降级创建)

  • 文件:server/core/rule-engine.js
  • 位置:在 _applyAMLWithRetry() 方法之后添加
  • 操作:新增 async _stepDownCreate(applyAML, itemType, cleanProps, itemProperties, relationships) 方法:
  1. 步骤1:创建主对象(仅 properties),使用 buildAML({ item_type, action: 'add', properties: cleanProps })
  2. 步骤2:逐个创建 item_properties 子对象,通过 edit 主对象添加嵌套 Item
  3. 步骤3:逐个创建 relationships,通过 edit 主对象添加关系
  4. 任何步骤失败 → 调用 _rollbackCreatedItems() 回滚已创建对象
  5. 返回 { success: true/false, item_id, partial, failed_items }

步骤4:在 config.yaml 中添加重试策略配置

  • 文件:config.yaml
  • 位置:文件末尾添加新配置段
  • 操作:添加 aras_retry 配置段:
  aras_retry:
    max_retries: 3
    permission_retry: 1
    uniqueness_retry: 3
    timeout_retry: 1
    backoff_base_ms: 1000
  
  • 参考代码:design §4.2.5 第1485-1497行

#### 验证方法

  1. 测试权限错误重试:构造权限错误响应,验证注入 World 权限后重试
  2. 测试唯一性冲突重试:构造 not unique 错误,验证 item_number 追加后缀重试
  3. 测试分步降级:构造嵌套 AML 整体提交失败场景,验证自动降级为分步创建
  4. 测试超时重试:验证超时后重试1次
  5. 测试其他错误指数退避:验证 1s、2s、4s 退避间隔

TASK-P1-03: 后端创建路径回滚机制

  • 对应需求:P1-5.4(spec §5.4,回滚部分)
  • 优先级:P1
  • 依赖任务:TASK-P1-02(重试机制先实现,回滚在重试失败后触发)
  • 预估工作量:1天

#### 实现步骤

步骤1:在 rule-engine.js 中新增 _rollbackCreatedItems() 方法

  • 文件:server/core/rule-engine.js
  • 位置:在 _stepDownCreate() 方法之后添加
  • 操作:新增 async _rollbackCreatedItems(applyAML, createdIds) 方法:
  1. 遍历 createdIds[{ item_type, item_id }]),对每个对象发送 AML
  2. 删除成功 → 加入 rolledBackIds,记录审计日志 [AUDIT] rollback_delete(含 action、item_type、item_id、reason、timestamp)
  3. 删除失败 → 加入 orphanIds,记录 [CRITICAL] 日志
  4. 返回 { rolled_back: orphanIds.length === 0, rolled_back_ids: rolledBackIds, orphan_ids: orphanIds }
  • 参考代码:design §1.3.4 第858-892行

步骤2:在 _stepDownCreate() 中集成回滚

  • 文件:server/core/rule-engine.js
  • 位置:_stepDownCreate() 方法内
  • 操作:
  1. 维护 createdIds 数组,记录每步成功创建的对象
  2. 任何步骤失败 → 调用 _rollbackCreatedItems(applyAML, createdIds) 回滚
  3. 回滚结果附加到返回值中:{ ..., rollback_result: { rolled_back, rolled_back_ids, orphan_ids } }

步骤3:在 createItem() 中集成回滚

  • 文件:server/core/rule-engine.js
  • 位置:createItem() 方法中多步骤创建逻辑
  • 操作:
  1. 维护 createdIds 数组,记录主对象和子对象创建成功的 ID
  2. 后续步骤失败时 → 调用 _rollbackCreatedItems(applyAML, createdIds) 回滚
  3. 回滚结果附加到返回值中

#### 验证方法

  1. 测试回滚:构造步骤3失败场景,验证步骤1和2创建的对象被删除
  2. 测试回滚本身失败:模拟回滚删除失败,验证返回 orphan_ids
  3. 验证审计日志:检查 [AUDIT] rollback_delete 日志包含操作时间、对象ID、回滚原因
  4. 测试部分回滚:验证已回滚和未回滚的对象正确分类

TASK-P1-04: 前端 create_post 规则执行可靠性

  • 对应需求:P1-5.5(spec §5.5)
  • 优先级:P1
  • 依赖任务:无
  • 预估工作量:2天

#### 实现步骤

步骤1:在 rule-engine.js 中新增 executeCreatePost() 方法

  • 文件:server/core/rule-engine.js
  • 位置:在 createItem() 方法之后添加
  • 操作:新增 async executeCreatePost(context, options = {}) 方法:
  1. 参数:context = { item_type, item_id, properties, relationships }options = { maxRetries: 2, timeout: 30000 }
  2. 校验:item_typeitem_id 缺少 → 返回 { success: false, error: '缺少 item_type 或 item_id' }
  3. 循环 attempt = 0..maxRetries
  • 使用 Promise.race 实现30秒超时:this.execute('create_post', postContext, { conflict_strategy: 'merge' })
  • 成功 → 记录审计日志 [AUDIT] create_post,返回 { success: true, rule_results, retry_count, elapsed }
  • 失败 → 记录审计日志 [AUDIT] create_post_failed,指数退避重试(1s、2s)
  1. 全部重试失败 → 返回 { success: false, error, rule_results: [], retry_count: maxRetries }
  • 参考代码:design §1.3.5 第976-1051行

步骤2:在 server.js 中新增 /api/rule-engine/execute-create-post 端点

  • 文件:server.js
  • 位置:在现有 /api/rule-engine/ 路由处理区域附近
  • 操作:
  1. 新增 pathname === '/api/rule-engine/execute-create-post' 路由判断
  2. POST 方法,先 collectBody(req) 获取 bodyStr,解析 JSON
  3. 校验 item_typeitem_id 必填
  4. 调用 engine.executeCreatePost({ item_type, item_id, properties, relationships }, { maxRetries: 2, timeout: 30000 })
  5. 返回 { success: result.success, data: result }
  • 参考代码:design §1.3.5 第1059-1077行

步骤3:在前端 useCapabilityCreate.js 中新增 executeCreatePost() 方法

  • 文件:src/composables/useCapabilityCreate.js
  • 位置:在创建成功后的处理逻辑中添加
  • 操作:
  1. 新增 async function executeCreatePost(itemType, itemId, properties, relationships) 方法
  2. 调用 POST /api/rule-engine/execute-create-post,body 为 { item_type, item_id, properties, relationships }
  3. 成功 → console.log('[useCapabilityCreate] create_post 执行成功')
  4. 失败 → console.warn('[useCapabilityCreate] create_post 执行失败'),设置 error.value = '对象创建成功,但后续处理失败:${error}'
  5. 不回滚主对象,仅通知用户
  • 参考代码:design §1.3.5 第1084-1118行

步骤4:在创建成功后自动调用 executeCreatePost()

  • 文件:src/composables/useCapabilityCreate.js
  • 位置:在 AML 提交成功、提取 itemId 之后
  • 操作:
  1. 在创建成功后调用 executeCreatePost(itemType, itemId, properties, relationships)
  2. create_post 结果不影响主对象创建成功的判定
  3. create_post 失败时展示提示,但主对象创建结果保持 success: true

步骤5:新增 create_post_results 持久化表

  • 文件:server.js 或数据库初始化脚本
  • 操作:
  1. 新建 create_post_results 表:
     CREATE TABLE IF NOT EXISTS create_post_results (
       id INTEGER PRIMARY KEY AUTOINCREMENT,
       item_type TEXT NOT NULL,
       item_id TEXT NOT NULL,
       success INTEGER NOT NULL DEFAULT 0,
       rule_results TEXT,
       error TEXT,
       retry_count INTEGER DEFAULT 0,
       created_at TEXT DEFAULT (datetime('now','localtime')),
       delivered INTEGER DEFAULT 0,
       delivered_at TEXT
     );
     
  1. 创建索引:idx_post_results_itemidx_post_results_undelivered
  2. executeCreatePost() 中持久化执行结果
  • 参考代码:design §1.3.5 第1126-1140行

#### 验证方法

  1. 前端创建对象成功后,验证自动调用 /api/rule-engine/execute-create-post
  2. 模拟 create_post 规则执行成功,验证前端收到成功通知
  3. 模拟 create_post 规则执行失败,验证前端收到失败提示,主对象不回滚
  4. 模拟 create_post 规则执行超时(>30秒),验证前端收到超时提示
  5. 检查 create_post_results 表中记录了执行结果
  6. 验证重试机制:create_post 第一次失败后自动重试,最多2次

P2 优先级任务(同步维护,可延后实施)


TASK-P2-01: 前后端创建逻辑同步维护

  • 对应需求:P2-5.6(spec §5.6)
  • 优先级:P2
  • 依赖任务:TASK-P0-03(AMLGenerator item_properties 补齐后,才能对比前后端输出一致性)
  • 预估工作量:2天

#### 实现步骤

步骤1:为 aml-builder.js 添加 @mirror-of 文件头标注

  • 文件:server/utils/aml-builder.js
  • 位置:文件头部(第1行之前)
  • 操作:添加文件头注释:
  /**
   * 服务端 AML 构建器 - 将标准 JSON 格式转换为 SCSAI AML
   * 
   * @mirror-of src/utils/AmlBuilder.js
   * @last-sync 2026-06-26
   * @sync-status drifted
   * 
   * ⚠️ 此文件逻辑必须与前端 src/utils/AmlBuilder.js 保持完全一致
   * 前端逻辑经过反复测试(十几种复杂业务对象),后端不得自创逻辑
   * 
   * 已知差异(drifted 项):
   * 1. 前端有 _formatValue() 方法(list值匹配、日期格式化),后端无
   * 2. 前端 esc() 不转义单引号,后端可能转义
   * 3. 前端 buildRelationshipElement 支持 isSameType 分支,后端无
   */
  
  • 参考代码:design §1.3.6 第1172-1188行

步骤2:为 unified-create.js 添加 @mirror-of 文件头标注

  • 文件:server/routes/unified-create.js
  • 位置:文件头部
  • 操作:添加文件头注释:
  /**
   * unified-create.js — 服务端统一对象创建 API
   * 
   * @mirror-of src/composables/useCapabilityCreate.js
   * @last-sync 2026-06-26
   * @sync-status drifted
   * 
   * 镜像 src/composables/useCapabilityCreate.js 的创建流程
   * 
   * 已知差异(drifted 项):
   * 1. 前端10步完整流程(含AI纠错3次重试),后端7步简化流程
   * 2. 前端有 _dualDbDedupCheck 双库查重,后端无
   * 3. 前端有 precreateNestedItem 预创建,后端有简化版
   * 4. 前端有权限重试(World权限),后端有
   * 5. 前端有去重重试(追加后缀),后端有
   */
  
  • 参考代码:design §1.3.6 第1193-1209行

步骤3:新增 aml-builder-consistency.test.js 自动化测试

  • 文件:tests/aml-builder-consistency.test.js(新建)
  • 操作:
  1. 导入 const { buildAML: serverBuildAML } = require('../server/utils/aml-builder')
  2. 定义测试用例(5组):
  • 普通属性:{ item_type: 'Part', action: 'add', properties: { name: '测试零件', item_number: 'P-001' } }
  • 含 item_properties(嵌套创建)
  • 含 item_properties(引用已有)
  • 含 relationships
  • 完整三层结构
  1. 每个测试用例验证:输出非空、包含 //type="..."/action="..." 结构、item_properties 嵌套结构正确、relationships 结构正确
  • 参考代码:design §1.3.6 第1214-1316行

步骤4:新增 create-flow-consistency.test.js 自动化测试

  • 文件:tests/create-flow-consistency.test.js(新建)
  • 操作:
  1. 对比前端 useCapabilityCreate.js 和后端 unified-create.js 的流程步骤
  2. 验证关键步骤一致性:属性清洗逻辑、AML 构建使用相同的 buildAML()、权限重试策略、去重重试策略
  3. 检测差异时输出 WARNING(不阻断 CI,但提醒开发团队)

#### 验证方法

  1. 运行 node --test tests/aml-builder-consistency.test.js,验证所有测试用例通过
  2. 检查 aml-builder.js 文件头包含 @mirror-of src/utils/AmlBuilder.js
  3. 检查 unified-create.js 文件头包含 @mirror-of src/composables/useCapabilityCreate.js
  4. 故意修改 aml-builder.js 的输出格式,验证测试检测到差异

验证与集成测试


TASK-VAL-01: P0 端到端集成验证

  • 对应需求:P0-5.1, P0-5.2, P0-5.3
  • 优先级:P0(与最后一个P0任务同步完成)
  • 依赖任务:TASK-P0-01, TASK-P0-02, TASK-P0-03, TASK-P0-04
  • 预估工作量:1天

#### 实现步骤

步骤1:启动服务验证

  • 操作:
  1. 执行 node server.js,确认无启动报错
  2. 检查控制台日志中规则引擎初始化成功

步骤2:generate→前端创建闭环端到端验证

  • 操作:
  1. 调用 POST /api/capability,body 为 { "capability": "generate", "params": { "item_type": "Part", "data": { "name": "测试零件" } } }
  2. 验证返回 generated_content 为标准格式 { item_type, properties, item_properties, relationships }
  3. 前端测试:generate 成功后自动启动创建流程
  4. 测试 autoCreate: false,验证仅展示不创建
  5. 测试 generate 失败场景,验证生成内容不丢失

步骤3:AMLGenerator item_properties 端到端验证

  • 操作:
  1. 通过 create 能力创建包含 item_properties 的数据
  2. 验证 AMLGenerator 输出嵌套 Item 结构
  3. 对比 AMLGenerator 和 AmlBuilder 对同一数据的输出,验证一致性
  4. 测试 item/foreign 类型字段自动识别

步骤4:关系格式转换端到端验证

  • 操作:
  1. 通过 create 能力传入 batch_items,验证关系发现结果正确转换
  2. 验证传入 AmlBuilder 的 relationships 为标准格式(无 source_index/target_index)
  3. 测试关系发现失败场景(非阻塞,不影响主对象创建)

步骤5:回归测试

  • 操作:
  1. 验证现有 create/repair/optimize/compare/identify 能力不受影响
  2. 验证前端直接提交模式(/aras-api/ApplyItem)不受影响
  3. 验证后端 create-item 端点的 applyAML:null 预览模式不受影响

TASK-VAL-02: P1 集成验证

  • 对应需求:P1-5.4, P1-5.5
  • 优先级:P1
  • 依赖任务:TASK-P1-01, TASK-P1-02, TASK-P1-03, TASK-P1-04
  • 预估工作量:0.5天

#### 实现步骤

步骤1:后端创建路径重试与回滚验证

  • 操作:
  1. 模拟 SCSAI 返回权限错误,验证 World 权限注入重试
  2. 模拟唯一性冲突,验证 item_number 追加后缀重试
  3. 模拟超时,验证返回结构化错误而非抛异常
  4. 测试分步降级:嵌套 AML 失败后自动降级为分步创建
  5. 测试回滚:多步骤创建失败后回滚已创建对象
  6. 测试回滚本身失败:模拟回滚删除失败,验证返回 orphan_ids

步骤2:create_post 可靠性验证

  • 操作:
  1. 前端创建对象成功后,验证自动调用 create_post 端点
  2. 模拟 create_post 规则执行失败,验证前端收到失败提示
  3. 模拟 create_post 规则执行超时,验证30秒超时返回
  4. 验证 create_post 失败不回滚主对象
  5. 验证重试机制(最多2次,指数退避)
  6. 检查 create_post_results 表中持久化记录

依赖关系图

TASK-P0-01 (generate输出标准化-rule-engine) ──→ TASK-P0-02 (generate输出标准化-runtime+前端)
TASK-P0-03 (AMLGenerator item_properties补齐) ──→ TASK-P1-02 (重试机制) ──→ TASK-P1-03 (回滚机制)
TASK-P0-04 (关系发现格式转换)                         ↑
    │                                          TASK-P1-01 (aras-client超时结构化)
    ├────→ TASK-P1-04 (create_post可靠性) ──── 无前置依赖
    │
    ├────→ TASK-P2-01 (前后端同步维护) ── 依赖 P0-03
    │
    ├────→ TASK-VAL-01 (P0端到端验证) ── 依赖 P0-01, P0-02, P0-03, P0-04
    │
    └────→ TASK-VAL-02 (P1集成验证) ── 依赖 P1-01, P1-02, P1-03, P1-04

建议实施顺序

P0-01 → P0-02 → P0-03 → P0-04 → P1-01 → P1-02 → P1-03 → P1-04 → P2-01 → VAL-01 → VAL-02

修改文件汇总

| 文件路径 | 涉及任务 | 修改要点 |

|---------|---------|---------|

| server/core/rule-engine.js | P0-01, P1-02, P1-03, P1-04 | _standardizeGeneratedContent()_applyAMLWithRetry()_rollbackCreatedItems()_stepDownCreate()executeCreatePost()createItem() 重试集成 |

| server/core/capability-runtime.js | P0-02, P0-04 | generate() 标准化输出、create() 关系格式转换、_standardizeGeneratedContent() |

| server/core/aml-generator.js | P0-03 | _buildAML() item_properties 支持、_buildItemPropertiesXml() 新增 |

| server/core/relationship-resolver.js | P0-04 | convertDiscoveryRelations() 静态方法新增 |

| server/utils/aras-client.js | P1-01 | _sendRequest() 超时返回结构化错误、sendAML() 超时/HTTP错误处理 |

| server/utils/aml-builder.js | P2-01 | 文件头 @mirror-of 标注 |

| server/routes/unified-create.js | P2-01 | 文件头 @mirror-of 标注 |

| src/composables/useCapabilityCreate.js | P0-02, P1-04 | createFromGenerate() 新增、executeCreatePost() 新增、创建成功后调用 create_post |

| server.js | P1-04 | 新增 /api/rule-engine/execute-create-post 端点 |

| config.yaml | P1-02 | 新增 aras_retry 配置段 |

| tests/aml-builder-consistency.test.js | P2-01 | 新增前后端 AmlBuilder 一致性测试 |

| tests/create-flow-consistency.test.js | P2-01 | 新增前后端创建流程一致性测试 |

新增方法/函数汇总

方法名文件任务说明
_standardizeGeneratedContent()rule-engine.jsP0-01标准化 generate 输出为前端可消费格式
_standardizeGeneratedContent()capability-runtime.jsP0-02标准化 generate 输出(与 rule-engine.js 逻辑一致)
createFromGenerate()useCapabilityCreate.jsP0-02从 generate 输出创建对象
_buildItemPropertiesXml()aml-generator.jsP0-03构建 item_properties 嵌套 XML
convertDiscoveryRelations()relationship-resolver.jsP0-04关系发现格式转换(静态方法)
_applyAMLWithRetry()rule-engine.jsP1-02带重试的 AML 提交
_stepDownCreate()rule-engine.jsP1-02分步降级创建
_rollbackCreatedItems()rule-engine.jsP1-03回滚已创建的对象
executeCreatePost()rule-engine.jsP1-04执行 create_post 规则(带重试和超时)
executeCreatePost()useCapabilityCreate.jsP1-04前端调用 create_post 端点
← 返回案例列表
分享:
🤖 Try Now →
🤖
🎁