六能力写回闭环修复执行记录
日期: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:false、changes:{}),无任何回写代码。
实测写回探针显示:repair 返回 source: relationship_resolver、aras_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 === 0 为 false,fetched 的 SCSAI 真实对象被静默丢弃,context.data.id 始终为 undefined。
后果链:
context.data.id === undefined→ repair 的objectAlreadyResolved为 false- → 进入
relationship-resolver.resolveExistence分支 - → resolver 用独立 client 查刚创建对象,误判
status='new' - → repair 早返回
source: relationship_resolver,规则引擎根本不执行 - → 即便给正常对象,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 + _applyOptimizeToARAS)
optimize在auto_apply=true且规则产出changes非空时,调用新增的_applyOptimizeToARAS回写(action=edit)。- 新增
_applyOptimizeToARAS(itemType, itemId, optimizations, context):复用与_applyRepairToARAS相同的 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_engine,repairs=[{rule:'物料单位标准化', changes:{unit:'EA'}}],aras_result.success=true - DIRECT GET(ArasClient 按 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清场 + 单实例启动解决
六、遗留/后续
identify的query_type:'get'+filters:{item_number}在该姿势下返回空(executeIdentify的get分支未实现,落到 default 空结果);用selected_ids或query_type:'list'可正常查。非写回阻塞项,建议后续补get分支或统一查询姿势。- optimize 当前规则均为纯建议(changes 空),需补充带
changes的优化规则才能触发实际回写(代码路径已就绪)。 - 关系型 ItemType(Model/Property 等 is_relationship=1)的修复/优化回写未专门验证,建议后续补测。
BossAgents