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)方法,处理以下情况:
- 已是标准格式(含
item_type+properties)→ 直接返回 - 字符串 → 尝试 JSON 解析(正则提取
{...}块),解析失败 → 包装为{ item_type, properties: { description: rawContent }, _unparseable: true } - 解析后有
properties字段但无item_type→ 注入item_type,补齐item_properties和relationships - 扁平属性对象 → 提取
relationships/item_properties,其余归入properties - 无法解析 → 包装为
{ 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()返回值构建处 - 操作:
- 在第1718行
generatedContent = best.result?.generated_content || best.result?.transformed_content || null;之后,调用generatedContent = this._standardizeGeneratedContent(generatedContent, item_type) - 返回值中的
generated_content使用标准化后的结果
- 参考代码:design §1.3.1 第158-208行
步骤3:确认 executeGenerate() 不自行调用 createItem()
- 文件:
server/core/rule-engine.js - 操作:审计
executeGenerate()代码路径(第1683-1731行),确认不包含对createItem()或applyAML()的直接调用 - 验收:代码审计通过,
executeGenerate()中无createItem/applyAML调用
#### 验证方法
- 启动服务
node server.js,确认无启动报错 - 调用
POST /api/capability,body 为{ "capability": "generate", "params": { "item_type": "Part", "data": { "name": "测试零件" } } } - 验证返回结果
generated_content包含{ item_type: 'Part', properties: {...}, item_properties: {}, relationships: [] }标准格式 - 测试 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()方法 - 操作:
- 在第781-784行规则引擎命中分支中,对
result.generated_content调用_standardizeGeneratedContent()标准化 - 在第788-797行 LLM 降级分支中,对
llmResult.data || llmResult.raw调用_standardizeGeneratedContent()标准化 - 新增
_standardizeGeneratedContent(rawContent, item_type)方法(逻辑与 rule-engine.js 中一致) - 在返回结果中添加
autoCreate标记:result.autoCreate = context.autoCreate !== false(默认 true)
- 参考代码:design §1.3.1 第216-310行
步骤2:在前端 useCapabilityCreate.js 中新增 createFromGenerate() 方法
- 文件:
src/composables/useCapabilityCreate.js - 位置:在现有
createObject()方法之后添加 - 操作:
- 新增
async function createFromGenerate(generatedContent, options = {})方法 - 格式校验:检查
generatedContent.item_type是否存在,不存在则设置error.value = '生成内容无法自动创建,请手动填写' - 保留生成内容:
result.value = { generated_content: generatedContent }(确保创建失败不丢失) autoCreate控制:options.autoCreate === false时仅展示,不自动创建- 自动创建:调用
createObject({ item_type, properties, item_properties, relationships })复用现有10步流程 - 创建失败时保留
generatedContent,设置error.value = '创建失败: ${e.message},生成内容已保留'
- 参考代码:design §1.3.1 第318-361行
步骤3:前端 generate 能力调用后自动衔接创建流程
- 文件:
src/composables/useCapabilityCreate.js(或调用 generate 能力的组件) - 操作:
- 在前端调用 generate 能力后,检查返回结果的
generated_content和autoCreate标记 autoCreate !== false时,自动调用createFromGenerate(generatedContent)generated_content._unparseable === true时,展示原始文本,提示"生成内容无法自动创建,请手动填写"
#### 验证方法
- 调用
POST /api/capability,body 为{ "capability": "generate", "params": { "item_type": "Part", "data": { "name": "测试零件" }, "autoCreate": true } } - 验证返回结果包含
autoCreate: true和标准格式generated_content - 前端测试:调用 generate 后验证自动启动创建流程
- 测试
autoCreate: false,验证仅展示不自动创建 - 测试 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)方法 - 操作:
- 在第352行
skipKeys数组中添加'item_properties'和'_item_properties' - 在属性 XML 构建的
.filter()中添加排除条件:key !== 'item_properties' && key !== '_item_properties' - 在属性 XML 构建的
.map()中添加 item/foreign 类型对象值检测:
dataType === 'item' || dataType === 'foreign'且typeof value === 'object'→ 转入itemProps[key] = value,返回nulldataType === 'item' || dataType === 'foreign'且值为字符串(GUID)→ 直接输出
- 在
.filter(Boolean)后添加过滤掉 null(被转入 item_properties 的字段) - 从
data.item_properties || data._item_properties || {}收集 item_properties - 在属性 XML 之后、relationships XML 之前,调用
_buildItemPropertiesXml(itemProps)生成嵌套 XML - 将
itemPropsXml拼接到propertiesXml之后
- 参考代码:design §1.3.2 第424-480行
步骤2:新增 _buildItemPropertiesXml() 方法
- 文件:
server/core/aml-generator.js - 位置:在
_buildAML()方法之后、_buildRelationshipsXml()方法之前添加 - 操作:新增
_buildItemPropertiesXml(itemProperties)方法,与aml-builder.js的buildItemElement()第60-76行逻辑一致:
- 遍历
itemProperties对象 action === 'add'且有item_type→ 嵌套创建:输出- 子属性
- 子属性遍历
propDef.properties,非对象值直接输出 - 不支持更深层嵌套(超过3层记录 WARNING 日志)
action === 'get'且有id和item_type→ 引用已有:输出- 所有文本值通过
this._escapeXml()转义 - 无 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()调用
#### 验证方法
- 构造包含 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' });
- 验证输出 AML 包含
嵌套结构测试 WBS - 测试
action: 'get'引用格式:验证输出 - 测试 schema 中 item/foreign 类型字段自动识别:
wbs_id类型为item且值为对象 → 自动按 item_properties 嵌套输出 - 对比
aml-builder.js的buildItemElement()对同一数据的输出,验证 item_properties 部分完全一致 - 测试无 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)方法:
- 入参校验:
discoveredRelations和batchItems非数组或为空 → 返回[] - 按
relation_type分组:遍历discoveredRelations,提取rel.relation_type || rel.relationship_type relation_type为空 → 跳过,记录 WARNING 日志 "关系类型为空,跳过"- 索引解析:
parentIdx = rel.parent_index ?? rel.source_index,childIdx = rel.child_index ?? rel.target_index - 索引越界检查:
parentIdx < 0 || parentIdx >= batchItems.length→ 跳过,记录 WARNING 日志 "关系索引越界" - 提取
related_item_type:batchItems[childIdx].item_type || mainItemType(缺少 item_type 时使用主类型降级,记录 WARNING) - 构建
relatedItem:{ properties: { ...batchItems[childIdx] } },附加关系级别属性 - 校验转换结果:
relationship_type非空字符串且related_items非空数组,不通过则跳过 - 返回 AmlBuilder 标准格式数组
- 参考代码:design §1.3.3 第560-635行
步骤2:修改 capability-runtime.js 的 create() 方法,集成格式转换
- 文件:
server/core/capability-runtime.js - 位置:第871-893行,关系发现结果处理处
- 操作:
- 在第880-888行,将当前直接 push
source_index/target_index格式的逻辑替换为格式转换 - 导入
RelationshipResolver:const { RelationshipResolver } = require('./relationship-resolver');(如尚未导入) - 调用
RelationshipResolver.convertDiscoveryRelations(discoveredRelations, context.batch_items, item_type)转换 - 将转换后的标准格式关系 push 到
relationships数组 - 保留 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字段
#### 验证方法
- 构造测试数据:
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');
- 验证输出为
[{ relationship_type: 'Part BOM', related_item_type: 'Part', related_items: [...] }] - 测试索引越界:
parent_index: 99→ 跳过该关系,返回空数组 - 测试
relation_type为空 → 跳过,返回空数组 - 端到端测试:通过
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()回调 - 操作:
- 将超时处理从
reject(new Error('请求超时 (${this.timeout}ms)'))改为resolve({ statusCode: 0, headers: {}, data: '', timeoutError: true, timeoutMs: this.timeout }) - 这样
sendAML()可以统一处理超时响应,而非调用方 try-catch
- 参考代码:design §1.3.4 第704-723行
步骤2:修改 aras-client.js 的 sendAML() 处理超时和 HTTP 错误
- 文件:
server/utils/aras-client.js - 位置:
sendAML()方法中_sendRequest()调用之后 - 操作:
- 添加超时响应处理:
response.timeoutError→ 返回{ success: false, items: [], fault: { code: 'TIMEOUT', string: 'SCSAI请求超时 (Xms)', detail: 'timeout after Xms' }, rawXml: '', count: 0 } - 添加 HTTP 错误处理:
statusCode >= 400→ 返回{ success: false, items: [], fault: { code: 'HTTP_ERROR', string: 'HTTP XXX', detail: response.data }, rawXml: response.data, count: 0 } - 正常响应继续调用
_parseResponse(response.data)
- 参考代码:design §1.3.4 第729-767行
步骤3:确认 _parseFault() 方法可用且被 sendAML() 统一使用
- 文件:
server/utils/aras-client.js - 操作:确认
_parseFault()方法(第137行)已存在且被_parseResponse()正确调用,SOAP Fault 解析路径统一
#### 验证方法
- 测试 aras-client.js 超时:模拟超时场景,验证返回
{ success: false, fault: { code: 'TIMEOUT' } }而非抛异常 - 测试 HTTP 错误:模拟 500 响应,验证返回
{ success: false, fault: { code: 'HTTP_ERROR' } } - 测试正常 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)方法:
- 最大重试次数
maxRetries = 3,循环attempt = 0..maxRetries - 每次调用
applyAML(currentAml),成功(result.items?.length > 0 || result.Item)→ 返回{ result, retryCount: attempt, retryReasons } - 解析错误
fault = result?.fault || {},faultCode = fault.code || '',faultString = fault.string || '' - 权限错误(
/no default permission|permission_id|access denied/i)→ 注入 World 权限重试1次 - 唯一性冲突(
/not unique|PropertiesAreNotUnique/i)→item_number追加后缀-1/-2/-3,最多3次 - 超时(
faultCode === 'TIMEOUT')→ 重试1次 - 其他错误 → 指数退避重试(1s、2s、4s)
- 全部重试失败 → 返回
{ result, retryCount, retryReasons, finalFault: fault }
- 参考代码:design §1.3.4 第782-851行
步骤2:修改 rule-engine.js 的 createItem() 集成重试
- 文件:
server/core/rule-engine.js - 位置:第2538-2550行,applyAML 调用处
- 操作:
- 将
const result = await applyAML(aml)替换为const { result: applyResult, retryCount, finalFault } = await this._applyAMLWithRetry(applyAML, aml, context) - 从
applyResult中提取itemId(保持现有稳健提取逻辑) itemId为空时,检查是否有嵌套数据且重试过 → 调用_stepDownCreate()分步降级- 分步降级成功 →
itemId = stepDownResult.item_id - 分步降级失败 → 返回
{ 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:创建主对象(仅 properties),使用
buildAML({ item_type, action: 'add', properties: cleanProps }) - 步骤2:逐个创建 item_properties 子对象,通过 edit 主对象添加嵌套 Item
- 步骤3:逐个创建 relationships,通过 edit 主对象添加关系
- 任何步骤失败 → 调用
_rollbackCreatedItems()回滚已创建对象 - 返回
{ 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行
#### 验证方法
- 测试权限错误重试:构造权限错误响应,验证注入 World 权限后重试
- 测试唯一性冲突重试:构造
not unique错误,验证item_number追加后缀重试 - 测试分步降级:构造嵌套 AML 整体提交失败场景,验证自动降级为分步创建
- 测试超时重试:验证超时后重试1次
- 测试其他错误指数退避:验证 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)方法:
- 遍历
createdIds([{ item_type, item_id }]),对每个对象发送AML - 删除成功 → 加入
rolledBackIds,记录审计日志[AUDIT] rollback_delete(含 action、item_type、item_id、reason、timestamp) - 删除失败 → 加入
orphanIds,记录[CRITICAL]日志 - 返回
{ 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()方法内 - 操作:
- 维护
createdIds数组,记录每步成功创建的对象 - 任何步骤失败 → 调用
_rollbackCreatedItems(applyAML, createdIds)回滚 - 回滚结果附加到返回值中:
{ ..., rollback_result: { rolled_back, rolled_back_ids, orphan_ids } }
步骤3:在 createItem() 中集成回滚
- 文件:
server/core/rule-engine.js - 位置:
createItem()方法中多步骤创建逻辑 - 操作:
- 维护
createdIds数组,记录主对象和子对象创建成功的 ID - 后续步骤失败时 → 调用
_rollbackCreatedItems(applyAML, createdIds)回滚 - 回滚结果附加到返回值中
#### 验证方法
- 测试回滚:构造步骤3失败场景,验证步骤1和2创建的对象被删除
- 测试回滚本身失败:模拟回滚删除失败,验证返回
orphan_ids - 验证审计日志:检查
[AUDIT] rollback_delete日志包含操作时间、对象ID、回滚原因 - 测试部分回滚:验证已回滚和未回滚的对象正确分类
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 = {})方法:
- 参数:
context = { item_type, item_id, properties, relationships },options = { maxRetries: 2, timeout: 30000 } - 校验:
item_type和item_id缺少 → 返回{ success: false, error: '缺少 item_type 或 item_id' } - 循环
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)
- 全部重试失败 → 返回
{ 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/路由处理区域附近 - 操作:
- 新增
pathname === '/api/rule-engine/execute-create-post'路由判断 - POST 方法,先
collectBody(req)获取 bodyStr,解析 JSON - 校验
item_type和item_id必填 - 调用
engine.executeCreatePost({ item_type, item_id, properties, relationships }, { maxRetries: 2, timeout: 30000 }) - 返回
{ success: result.success, data: result }
- 参考代码:design §1.3.5 第1059-1077行
步骤3:在前端 useCapabilityCreate.js 中新增 executeCreatePost() 方法
- 文件:
src/composables/useCapabilityCreate.js - 位置:在创建成功后的处理逻辑中添加
- 操作:
- 新增
async function executeCreatePost(itemType, itemId, properties, relationships)方法 - 调用
POST /api/rule-engine/execute-create-post,body 为{ item_type, item_id, properties, relationships } - 成功 →
console.log('[useCapabilityCreate] create_post 执行成功') - 失败 →
console.warn('[useCapabilityCreate] create_post 执行失败'),设置error.value = '对象创建成功,但后续处理失败:${error}' - 不回滚主对象,仅通知用户
- 参考代码:design §1.3.5 第1084-1118行
步骤4:在创建成功后自动调用 executeCreatePost()
- 文件:
src/composables/useCapabilityCreate.js - 位置:在 AML 提交成功、提取
itemId之后 - 操作:
- 在创建成功后调用
executeCreatePost(itemType, itemId, properties, relationships) - create_post 结果不影响主对象创建成功的判定
- create_post 失败时展示提示,但主对象创建结果保持
success: true
步骤5:新增 create_post_results 持久化表
- 文件:
server.js或数据库初始化脚本 - 操作:
- 新建
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
);
- 创建索引:
idx_post_results_item和idx_post_results_undelivered - 在
executeCreatePost()中持久化执行结果
- 参考代码:design §1.3.5 第1126-1140行
#### 验证方法
- 前端创建对象成功后,验证自动调用
/api/rule-engine/execute-create-post - 模拟 create_post 规则执行成功,验证前端收到成功通知
- 模拟 create_post 规则执行失败,验证前端收到失败提示,主对象不回滚
- 模拟 create_post 规则执行超时(>30秒),验证前端收到超时提示
- 检查
create_post_results表中记录了执行结果 - 验证重试机制: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(新建) - 操作:
- 导入
const { buildAML: serverBuildAML } = require('../server/utils/aml-builder') - 定义测试用例(5组):
- 普通属性:
{ item_type: 'Part', action: 'add', properties: { name: '测试零件', item_number: 'P-001' } } - 含 item_properties(嵌套创建)
- 含 item_properties(引用已有)
- 含 relationships
- 完整三层结构
- 每个测试用例验证:输出非空、包含
//type="..."/action="..."结构、item_properties 嵌套结构正确、relationships 结构正确
- 参考代码:design §1.3.6 第1214-1316行
步骤4:新增 create-flow-consistency.test.js 自动化测试
- 文件:
tests/create-flow-consistency.test.js(新建) - 操作:
- 对比前端 useCapabilityCreate.js 和后端 unified-create.js 的流程步骤
- 验证关键步骤一致性:属性清洗逻辑、AML 构建使用相同的 buildAML()、权限重试策略、去重重试策略
- 检测差异时输出 WARNING(不阻断 CI,但提醒开发团队)
#### 验证方法
- 运行
node --test tests/aml-builder-consistency.test.js,验证所有测试用例通过 - 检查
aml-builder.js文件头包含@mirror-of src/utils/AmlBuilder.js - 检查
unified-create.js文件头包含@mirror-of src/composables/useCapabilityCreate.js - 故意修改
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:启动服务验证
- 操作:
- 执行
node server.js,确认无启动报错 - 检查控制台日志中规则引擎初始化成功
步骤2:generate→前端创建闭环端到端验证
- 操作:
- 调用
POST /api/capability,body 为{ "capability": "generate", "params": { "item_type": "Part", "data": { "name": "测试零件" } } } - 验证返回
generated_content为标准格式{ item_type, properties, item_properties, relationships } - 前端测试:generate 成功后自动启动创建流程
- 测试
autoCreate: false,验证仅展示不创建 - 测试 generate 失败场景,验证生成内容不丢失
步骤3:AMLGenerator item_properties 端到端验证
- 操作:
- 通过 create 能力创建包含 item_properties 的数据
- 验证 AMLGenerator 输出嵌套 Item 结构
- 对比 AMLGenerator 和 AmlBuilder 对同一数据的输出,验证一致性
- 测试 item/foreign 类型字段自动识别
步骤4:关系格式转换端到端验证
- 操作:
- 通过 create 能力传入
batch_items,验证关系发现结果正确转换 - 验证传入 AmlBuilder 的 relationships 为标准格式(无 source_index/target_index)
- 测试关系发现失败场景(非阻塞,不影响主对象创建)
步骤5:回归测试
- 操作:
- 验证现有 create/repair/optimize/compare/identify 能力不受影响
- 验证前端直接提交模式(
/aras-api/ApplyItem)不受影响 - 验证后端 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:后端创建路径重试与回滚验证
- 操作:
- 模拟 SCSAI 返回权限错误,验证 World 权限注入重试
- 模拟唯一性冲突,验证 item_number 追加后缀重试
- 模拟超时,验证返回结构化错误而非抛异常
- 测试分步降级:嵌套 AML 失败后自动降级为分步创建
- 测试回滚:多步骤创建失败后回滚已创建对象
- 测试回滚本身失败:模拟回滚删除失败,验证返回
orphan_ids
步骤2:create_post 可靠性验证
- 操作:
- 前端创建对象成功后,验证自动调用 create_post 端点
- 模拟 create_post 规则执行失败,验证前端收到失败提示
- 模拟 create_post 规则执行超时,验证30秒超时返回
- 验证 create_post 失败不回滚主对象
- 验证重试机制(最多2次,指数退避)
- 检查
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.js | P0-01 | 标准化 generate 输出为前端可消费格式 |
| _standardizeGeneratedContent() | capability-runtime.js | P0-02 | 标准化 generate 输出(与 rule-engine.js 逻辑一致) |
| createFromGenerate() | useCapabilityCreate.js | P0-02 | 从 generate 输出创建对象 |
| _buildItemPropertiesXml() | aml-generator.js | P0-03 | 构建 item_properties 嵌套 XML |
| convertDiscoveryRelations() | relationship-resolver.js | P0-04 | 关系发现格式转换(静态方法) |
| _applyAMLWithRetry() | rule-engine.js | P1-02 | 带重试的 AML 提交 |
| _stepDownCreate() | rule-engine.js | P1-02 | 分步降级创建 |
| _rollbackCreatedItems() | rule-engine.js | P1-03 | 回滚已创建的对象 |
| executeCreatePost() | rule-engine.js | P1-04 | 执行 create_post 规则(带重试和超时) |
| executeCreatePost() | useCapabilityCreate.js | P1-04 | 前端调用 create_post 端点 |
BossAgents