六能力写回闭环修复执行记录

六能力写回闭环修复执行记录

日期:2026-07-11

主题:修复 repair/optimize 能力对 SCSAI 的写回闭环,使其与 create 一致真实落库

一、问题背景

此前六能力中只有 create 真实写回 SCSAI;repair/optimize 处于"建议模式":

  • repair:规则引擎已具备 _buildRepairAML / applyAMLFn 回写能力,但被 relationship-resolver.resolveExistence 早返回短路,且调用 executeRepair 时未传 item_id,导致 id 为 undefined,写回无法触发。
  • optimize:纯建议(auto_apply:falsechanges:{}),无任何回写代码

实测写回探针显示:repair 返回 source: relationship_resolver、SCSAI_result=null;optimize 的 item_id 为 null。

二、根因(关键发现)

根因 1:_resolveSelectedData 丢弃了选中的 SCSAI 对象(核心阻塞)

server/core/capability-runtime.js_resolveSelectedData 在拉回 SCSAI 真实对象后,用如下条件决定是否覆盖 context.data

if (!context.data || (typeof context.data === 'object' && Object.keys(context.data).length === 0)) {
  context.data = fetched.length === 1 ? fetched[0] : { items: fetched };
}

normalizeParams 已为 context.data 预填了一个非空对象(含 item_type/selected_ids 等字段),导致 Object.keys(context.data).length === 0false,fetched 的 SCSAI 真实对象被静默丢弃context.data.id 始终为 undefined。

后果链:

  1. context.data.id === undefined → repair 的 objectAlreadyResolved 为 false
  2. → 进入 relationship-resolver.resolveExistence 分支
  3. → resolver 用独立 client 查刚创建对象,误判 status='new'
  4. → repair 早返回 source: relationship_resolver,规则引擎根本不执行
  5. → 即便给正常对象,engine 拿不到 item_id,写回 AML 的 id 为 undefined

根因 2:optimize 缺回写分支

optimize 方法在 auto_apply 为 true 时无任何 SCSAI 写回逻辑,仅预留 auto_apply 字段。

根因 3:修复过程中暴露的端口/进程竞争

开发期间 3006 端口长期存在多个 server.js 残留进程(幽灵 PID),导致 HTTP 请求被路由到加载旧代码的进程,测试结论一度失真。已通过 taskkill /f 彻底清场、单一实例启动解决。

三、修复方案

修复 1:选中对象优先(capability-runtime.js _resolveSelectedData

将覆盖条件改为无条件覆盖——选中对象(selected_ids 拉回的 SCSAI 真实对象)优先于入参 data:

// 其余能力:单对象直接作为 data;多对象作为 data.items
// 选中对象优先于入参的 data/plain 对象,因此无条件覆盖
context.data = fetched.length === 1 ? fetched[0] : { items: fetched };

修复 2:repair 跳过 resolver 早返回(capability-runtime.js repair

_resolveSelectedData 已成功拉到 data.id,对象必然存在,跳过 resolver 二次存在性检测:

const objectAlreadyResolved = !!(data && data.id);
if (resolver && data && !options.skipExistenceCheck && !objectAlreadyResolved) {
  // ... resolver 逻辑(仅当未解析到对象时执行)
} else if (objectAlreadyResolved) {
  context._existing_match = { id: data.id };
}

修复 3:optimize 新增回写分支(capability-runtime.js optimize + _applyOptimizeToSCSAI

  • optimizeauto_apply=true 且规则产出 changes 非空时,调用新增的 _applyOptimizeToSCSAI 回写(action=edit)。
  • 新增 _applyOptimizeToSCSAI(itemType, itemId, optimizations, context):复用与 _applyRepairToSCSAI 相同的 edit AML 构造逻辑,将多个优化的 changes 合并后提交。

修复 4:repair 传 item_id(capability-runtime.js → rule-engine executeRepair

executeRepair 调用已改为 { item_type, item_id: data?.id, data, issues },确保规则引擎回写时持有目标对象 id。

四、验证结果(真实落库 SCSAI)

构造缺陷 Part(缺 unit 必填字段):

  • CREATE:unit=undefined
  • REPAIR:source=rule_enginerepairs=[{rule:'物料单位标准化', changes:{unit:'EA'}}]SCSAI_result.success=true
  • DIRECT GET(SCSAIClient 按 id 查):unit=EA ✅ 确认 SCSAI 真实被改写

全能力回归(单实例 PID 10684):

| 能力 | source | 写回状态 |

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

| create | unified-create | ✅ 直写落库 |

| repair | rule_engine | ✅ auto_apply 回写成功(实测 unit 被修) |

| optimize | rule_engine | ✅ 已有 auto_apply 回写分支(item_id 正确传入) |

| validate | rule_engine | ✅ 必填校验闭环(之前已修复) |

| identify | rule_engine | ✅ 查询/识别 |

| compare | rule_engine | ✅ 对比 |

五、清理

  • 移除调试用 wb_trace.log 临时写入代码(_resolveSelectedData / repair 内共 4 处)
  • 删除临时探针脚本(test_writeback_probe / test_id_probe / test_get_probe / test_q_probe / test_create_full / test_repair_real / test_final_regress / test_verify2)
  • 端口竞争问题通过 taskkill /f 清场 + 单实例启动解决

六、遗留/后续

  • identifyquery_type:'get' + filters:{item_number} 在该姿势下返回空(executeIdentifyget 分支未实现,落到 default 空结果);用 selected_idsquery_type:'list' 可正常查。非写回阻塞项,建议后续补 get 分支或统一查询姿势。
  • optimize 当前规则均为纯建议(changes 空),需补充带 changes 的优化规则才能触发实际回写(代码路径已就绪)。
  • 关系型 ItemType(Model/Property 等 is_relationship=1)的修复/优化回写未专门验证,建议后续补测。
← 返回案例列表
分享:
🤖 Try Now →
🤖
🎁