规则引擎校验结果截断 Bug 修复(2026-07-11 深夜 / 07-12 凌晨)
问题来源
上一轮复查发现反常:同一 item_type='Project',validate 用 selected_ids(真实对象)返回 9 条且 blocked=False,但用 data 直传空 Project 返回 4 条且 blocked=True,而 4 条里全部 matched=False —— 矛盾(被拦截却看不到是哪条规则拦截)。
两个真实 Bug
Bug 1:block 提前返回时未把拦截规则并入 results(结果不完整)
位置:server/core/rule-engine.js 的 execute() 循环。
原逻辑:
if (rule.action_type === 'block' && isBlocked) {
return { executed: true, blocked: true, block_reason: actionResult.message, results, ... };
}
results 此时只含之前已评估且 matched=false 的规则,触发拦截的当前规则 resultItem 未 push。
后果:HTTP 返回 blocked=True,但 results 里看不到那条 matched=true 的拦截规则,block_reason 指向一条 results 中不存在的规则 → 形成“全 false 却 blocked”的悖论。
修复:
- 返回前
results.push(resultItem); - 新增
blocking_rule: rule.id字段,前端可明确知道是哪条规则拦截。
Bug 2:validate 默认 first_match 策略会隐藏后续更严重的 block 违规
原 execute 默认 conflict_strategy='first_match'。规则按优先级排序后,P1(warn) 规则排在 P0(block) 之前(因 priority||2 使 P0=0 归为 2,P1=1 更小),若某 warn 规则先 matched=true,first_match 直接 break,后续 block 级必填校验(如 project-validate-001/003)永远不会被评估 → 校验结果漏报硬性违规。
后果:合法校验报告中本应标红的必填缺失被静默丢弃。
修复:默认策略按 scope 区分:
validate/inspect→merge(评估全部规则,收集所有违规);- 其余(repair/optimize 等)→ 保留
first_match(命中即应用首条自动修复,符合原意)。
block 分支仍作为终止条件(遇到首个 block 即返回),保证确定性。
验证(engine 直测 + HTTP 端到端)
- 空 Project(data-only):现
blocked=True, blocking_rule=builtin-project-validate-001,该规则matched=True出现在 results 中,悖论消除。 - 真实 Project(selected_ids):
blocked=False,9 条结果,仅通用规则命中且passed=True(非拦截),正确。 - 全能力回归:validate Part(6条,未拦截)/repair Part(1条回写)/optimize(4条)/inspect(618条) 全部正常,无回归。
附带确认(非 bug)
builtin-project-validate-003要求scheduling_method非空:真实 SCSAI Project 的scheduling_method为有效 ID 引用,属真实必填字段;之前“OK Project”测试数据漏传scheduling_method才触发拦截,引擎行为正确。- HTTP validate 与 engine 直测结果集差异,原以为是“project 规则缺失”,实为 Bug2 的
first_match提前 break 所致,现已统一。
修改文件
server/core/rule-engine.js:execute()两处(block 返回 push resultItem + blocking_rule;默认 conflict_strategy scope 化)。
MemoryService recordTrace 静默失败(同一轮发现并修复)
问题
server.err 每条请求都刷 [MemoryService] recordTrace失败: Cannot read properties of null (reading 'prepare')。
capability-dispatcher 以 fire-and-forget 调用 memoryService.extractAndStoreFacts,其失败被 try/catch 吞掉,
导致所有记忆写入(trace/fact/profile)长期静默丢失,且无任何有效告警之外的可观测信号。
根因
dbAdapter.init()是异步且不会翻转任何同步开关(dbAdapter._initialized始终 undefined),
旧 _getDb 在 _initialized 为假时返回 null。
sqliteCompat.createDatabase在 sql.js 未就绪时返回“延迟代理”,代理的prepare在_realDb未填充时抛错;
旧 _getDb 同步调用 prepare(...).run() 即抛,被吞 → this._db 永远为 null。
recordTrace原为同步,且extractAndStoreFacts未await它(先变成 Promise),
使后续 db.prepare 在 db 仍为 null 时崩溃。
修复(server/services/memory-service.js)
_getDb()改为仅返回已就绪实例(无则返 null,不再吞错建库)。- 新增
async _ensureDb():await dbAdapter.init()后dbAdapter.createDatabaseFresh(DB_PATH)(与规则引擎同款、server 内可用),再_initTables()。 recordTrace改为async,无 db 时await this._ensureDb()。extractAndStoreFacts改为async并await recordTrace;db缺失时安全返回。- 模块导出前
memoryService._ensureDb()预热,使读取类接口(getProfile/getFacts/getTraces)就绪。
验证
- 重启后发起一次 validate 请求,
boss_analytics.db的memory_traces表自动建好并写入 1 条
(source=web, action=validate),server.err 不再出现 recordTrace 报错。
修改文件汇总
server/core/rule-engine.js:execute()两处 +executeOptimize补rule_id。server/services/memory-service.js:_getDb/_ensureDb/recordTrace/extractAndStoreFacts+ 模块预热。server/core/health-inspector.js:_getDb改用createDatabaseFresh(规避 createDatabase 返回延迟代理、无.run()的建表失败)。
顺带修复 / 确认事项
1. optimize 返回缺 rule_id
executeOptimize 的 optimizations.push 只带 rule: rule.name,漏 rule_id → 前端/审计看不到是哪条规则。
已在 server/core/rule-engine.js 补 rule_id: rule.id,重启验证返回含 rule_id=builtin-optimize-00x。
2. HealthInspector 建表失败(this._db.run is not a function)
health-inspector.js 用 compat.createDatabase(dbPath) 在 sql.js 未就绪时拿到“延迟代理”(只有 prepare/exec,无 run),
导致 _ensureTables 的 CREATE TABLE ... .run() 抛错、健康检查静默失败。改为 compat.createDatabaseFresh(dbPath)(真实实例,
与规则引擎/记忆服务同款),重启后 server.err 不再出现 建表失败/保存结果失败。
3. 其余观察(非 bug)
identify早期返回空:是测试入参错位(传query而非query_type+filters),改为query_type=list后source=rule_engine正常返回。[RuleEngine] SCSAI私有库查询失败: 未知错误:仅冷启动一次性 SCSAI 查询失败,非系统性。配置模块加载失败,使用默认配置: Cannot find module './cron-tasks':配置回退告警,无害。
4. 六能力端到端稳定验证(真实 Part,重启后)
validate / inspect / repair(auto_apply) / optimize(auto_apply 真实回写 SCSAI) / identify / generate 全部 success=OK,无运行时报错。
optimize auto_apply=true 实测回写 SCSAI 成功(SCSAI_response.success=true,name/description 被改写)。
状态
- 全部修复完成,server 重启验证通过:六能力稳定、记忆写入恢复、健康检查表正常建好、无 recordTrace/建表/prepare 类报错。
- 无残留独立 bug。
BossAgents