create_post 规则闭环修复(2026-07-12)
主题:业务主创建路径(POST /api/unified/create)此前完全未触发规则引擎的 create_post 作用域,导致"创建后自动处理"类规则形同虚设。本次修复将断链接通,并明确"属性级回写 / 关系级留痕"的边界。
1. 背景与断链现象
系统有两条对象创建执行体系:
| 路径 | 入口 | 是否接规则引擎 |
|---|---|---|
| 规则引擎完整生命周期 | CapabilityRuntime.create → rule-engine.createItem | ✅ 有 validate → create_pre → 提交 → create_post 全链路 |
| 业务主创建路径(真实使用) | POST /api/unified/create → unified-create.js → handleCreate → SCSAI AML 直写 | ❌ 完全不接规则引擎 |
rule_engine.db 中确实存在 create_post 作用域规则(4 条内置):
builtin-project-create-post-001(Project:子任务编号补全)builtin-eco-create-post-001(ECO:自动关联变更对象)builtin-bom-create-post-001(Part:自动关联子零件)builtin-document-create-post-001(Document:自动关联文档类型)
但这些规则在真实创建时从未被调用——因为业务不走 rule-engine.createItem,而是走 unified-create.js 的纯直写流水线。这就是"create_post 不命中"的真因(此前误以为是查了一个不存在的 project-validate scope,实际是另一条断链)。
2. 根因
unified-create.js的handleCreate落库成功后直接return result,没有任何 hook 点调用规则引擎。CapabilityRuntime的规则引擎是懒初始化(_initRuleEngine()在每个能力方法内首次调用时才建),unified-create.js从不在创建时触发它。CapabilityRuntime只暴露了私有_getRuleEngine(),没有对外公开取引擎的方法;rule-engine.js本身也不持有单例。
3. 修复方案
3.1 文件改动清单
| 文件 | 改动 |
|---|---|
| server/core/capability-runtime.js | 新增公开方法 getRuleEngine()(返回已初始化引擎,未初始化则返回 null)+ ensureRuleEngine()(async,懒初始化,幂等) |
| server/routes/unified-create.js | 新增 runCreatePost(itemType, createdId, properties, relationships, SCSAIClient);在 handleCreate 的 Step 8(落库成功后、返回前)调用 |
3.2 runCreatePost 机制
handleCreate 落库成功 (createdId 有效)
└─> runCreatePost(...)
1. 复用 dispatcher 持有的 CapabilityRuntime 单例:
const { getRuntime } = require('../routes/capability-api');
const engine = await getRuntime().ensureRuleEngine();
2. engine.executeCreatePost({ item_type, item_id, properties, relationships })
3. 遍历命中规则的结果 (r.matched && r.result):
- 关系级改动 (out.relationships) → 记 createPost.relationshipHint(留痕,不回写)
- 属性级改动 (out.properties) → 构造 <Item action="edit" id=...> AML,真实回写 SCSAI
4. 整个流程包 try/catch:
失败只记 createPost.error 步骤,绝不阻断主创建结果
设计原则:宁可漏做也绝不误改。属性级 auto_fix 是安全的(edit 已存在对象的单个字段);关系级改动涉及已建关系的 re-fetch + 逐子项 edit,有 SCSAI 写风险,故只留痕、不开自动回写(见第 5 节边界)。
3.3 实例复用
通过 capability-api.getRuntime() 拿到与六能力同一个 CapabilityRuntime 单例,确保 create_post 与 validate/repair/optimize 等共享同一规则引擎实例(同一份 rule_engine.db、同一套已加载规则),避免重复初始化或实例不一致。
4. 验证结果(真实 SCSAI,HTTP 端到端)
服务器:node server.js(端口 3006),rule_engine.db 76 条规则。
用例 1:Part 创建(无 relationships)
POST /api/unified/create { itemType:'Part', properties:{ name, unit:'EA', description } }
→ success: true, id: E7AABB1624874DEE8960EF4810FD1B6B
→ steps 含: { step:'createPost', rules_applied: 1 }
引擎成功初始化并执行;Part 命中 bom-create-post(无 components 时为 no-op,但钩子确已运行)。
用例 2:Project + Project Tree 关系创建
POST /api/unified/create
{ itemType:'Project', properties:{ name, scheduling_mode, scheduling_type, dates },
relationships:[{ relationship_type:'Project Tree', related_item_type:'Project',
related_items:[{ properties:{ name:'Sub-A' } }] }] }
→ success: true, id: 6953B1B1D45E4812872179CE55773E23
→ steps 含:
{ step:'createPost', rules_applied: 1 }
{ step:'createPost.relationshipHint', rule:'builtin-project-create-post-001', relationships: 1 }
builtin-project-create-post-001 正确命中并检测到 1 条 Project Tree 关系,关系级改动记入 hint(未静默丢弃),主创建成功落库。
结论:create_post 断链已接通,钩子真实运行,主创建成功率不受影响。
5. 当前能力边界(已与用户确认:关系级先留痕)
| 能力 | 状态 | 说明 |
|---|---|---|
| create_post 规则触发 | ✅ 已接通 | handleCreate 落库后执行 executeCreatePost |
| 属性级 auto_fix 回写 | ✅ 就绪 | edit AML 真实回写 SCSAI;当前无属性级 auto_fix 规则命中实测,逻辑已验证 |
| 关系级改动回写 | ⚠️ 仅留痕 | 记入 createPost.relationshipHint,不自动回写(设计取舍,避免误改已建关系) |
| 主创建成功率 | ✅ 不受影响 | create_post 全程 try/catch,失败只记 warning |
已知口径说明
rules_applied当前统计的是"命中规则数"(r.matched && r.result),包含modified:false的规则(如 bom-create-post 无 components 时)。如需精确,可改为只统计result.modified === true,但不影响功能。
6. 后续可选项(未做,需决策)
- 关系级回写:对
project-create-post-001等,re-fetch 已建关系并逐子项 edit 补project_number。有 SCSAI 写风险,需单独评审。 rules_applied口径修正:改为只统计实际改动的规则(可选,纯展示优化)。
7. 关联文档
docs/写回闭环修复_2026-07-11.md— repair/optimize 回写闭环docs/规则引擎校验截断bug_2026-07-12.md— validate 闭环docs/复活死规则_2026-07-11.md— 规则引擎规则复活docs/规则引擎与六能力集成诊断_2026-07-11.md— 六能力与规则引擎集成总览
BossAgents