Reviving 25 Dead Rules — Execution Log (2026-07-11)

Reviving 25 Dead Rules — Execution Log (2026-07-11)

Root Cause

Among the rule engine's 76 built-in rules, approximately 25 rules have conditions that always evaluate to false (dead rules), causing capabilities like inspect/optimize/repair to idle. Two root cause categories:

Root Cause A: Double JSON-encoded condition (string trap)

The condition for repair-003/004/005/006, optimize-002/003/004 is written as JSON.stringify({type:'...'}) (a string).

In the engine's _evaluateCondition, const cond = rule.condition yields a string, cond.type=undefined → no type branch is entered → falls to default: return false.

These types are actually supported by the engine (has_non_standard_unit/has_price_anomaly/has_invalid_reference/has_bom_structure, etc.), but are killed by the string wrapper.

Root Cause B: condition.type not supported by the engine, and no condition_script fallback

inspect-001~006 (field_empty/field_pattern/field_value/multi_field_empty/field_empty_check/staleness_check),

valuate-001/002 (asset_count_check/income_data_check),

project-validate-001/002/003 (field_check),

validate-001/002 (type_check/length_check),

create_post project-001 (check_relationships),

repair-007~012 (has_price_change/has_missing_vendor_fields/has_low_stock/has_low_score/has_overdue_order/has_duplicate_candidates),

collect-001~005 (source_match/auto_catalog)

These types do not exist in the explicit branches of _evaluateCondition → fallback to false. Moreover, the original rules only have condition.type and no condition_script (the engine prioritizes the condition_script execution path), completely dead.

Root Cause C (Amplifier): _syncBuiltinRules INSERT missing the condition_script column

The INSERT column list in _syncBuiltinRules does not include condition_script; getRules parses row.condition_script via _safeParseJson, which is always null → even manually written condition_script gets REPLACED with NULL. The single source of truth, the definition change in _loadBuiltinRules(), is the correct fix path.

Fix actions (all in server/core/rule-engine.js)

  1. Add condition_script column to _syncBuiltinRules INSERT: add condition_script to the column list, add a corresponding ? to VALUES, and add rule.condition_script || null to stmt.run. Otherwise, any manually written condition_script will be cleared upon restart.
  2. Level 1 (Remove JSON.stringify, 4+3 items): Change condition: JSON.stringify({type:...}) to condition: {type:...} (object) for repair-003/004/005/006, optimize-002/003/004, allowing engine branches to match directly.
  3. Level 2 (Add condition_script, ~22 items): Add condition_script to all rules where the engine does not support the 'type' field, in the form (ctx,data)=>{...; return true/false;} (signature matches runSafeScript in _evaluateCondition).
  • Apply to inspect-001~006, valuate-001/002, project-validate-001/002/003, validate-001/002, create_post project-001, repair-007~012, collect-001~005.
  • For rules with existing action_script (repair/project-validate/create_post/inspect-005/006/valuate/collect-005), the condition_script is only responsible for 'whether it matches'; if matched, the existing action_script executes.
  • For rules with only condition.type and no action_script (inspect-001/002/003/004, validate-001/002): after condition_script matches, proceed with the default message from prompt_template/block/warn.

Verification Results (HTTP End-to-End After Clean Restart)

| Capability | Before Fix | After Fix |

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

| inspect (Part) | 0 issues | 618 issues (200 instance inspection, all 6 rules active) |

| optimize (Part) | 0 (engine.db interference) | 4 rule suggestions, source=rule_engine |

| validate (Part) | 6 rules | 6 rules stable, blocked=False |

| repair (Part) | Closed loop (previously verified) | Closed loop (repairs_applied=1) |

| repair (Vendor) | — | Short-circuited by relationship-resolver misjudging status='new' (separate bug, see below) |

| collect/valuate (main path covered by service) / create_post(project) | Backup path dead | Revived by adding condition_script to rule (Project-specific validation attributes in VALIDATE scope) |

Independent script verification (createDatabaseFresh + _evaluateCondition): All 6 inspect rules cond_script? true, inspect-001 returns matched=true when item_number is missing.

Secondary review (2026-07-11 evening) — In-depth verification of Vendor / Project / collect / valuate

Major clarification: The previous "repair Vendor short-circuit" was due to an expired test ID, not a code bug.

  • The previously used Vendor-001=6E0C9F7E2B6C4E74B2074F8B6F0EA6F8 simply does not exist in SCSAI (SCSAI returned 'No items of type 'Vendor' found').
  • Therefore, _resolveSelectedData could not fetch it → context.data had no id → entered resolver.resolveExistence → mistakenly judged as new → short-circuit.
  • After switching to a real Vendor ID (e.g., B1B97215420F412AA41F1D349668948F), the repair process completed fully: executed=True, issues_found=1, repairs_applied=2, source=rule_engine.
  • Conclusion: The repair Vendor rules (repair-003/008/010, etc.) are now active and correct; the previous issue was due to test data.

Project-specific rules have been reactivated (they belong to the VALIDATE scope, not a separate scope).

  • Clarification: The scope for builtin-project-validate-001/002/003 is RULE_SCOPES.VALIDATE + item_type_name='Project'. There is no separate project_validate scope (this was an error in previous documentation).
  • Validation test using a real Project (CBB360E3...): Returns 9 entries, including builtin-project-validate-001/002/003 (matched=False, as the real object is compliant) and generic rules (generic-required-check / generic-date-logic matched=True). This confirms the Project-specific rules are being executed.
  • builtin-project-create-post-001 (scope=create_post, item_type=Project) engine verification matched=false (create_post path not consumed, but rule remains active).

collect / valuate rule engine fallback path has been revived (main path overridden by service).

  • collect main path: data_collection_service (returns if service exists, does not enter rule engine). However, engine fallback path verification: execute('collect') → executed=true, 4 results, builtin-collect-001 matched=true (determined by source_match, hit). collect-001~005 all cond_script=true.
  • valuate main path: asset_valuator service. Engine fallback path: execute('valuate') → executed=true, builtin-valuate-001 matched=true. valuate-001/002 all cond_script=true.
  • Note: The "seemingly dead" behavior of collect/valuate is due to the main path service short-circuit; the rules themselves have been revived. To make them go through the rule engine, you need to lower the service priority or add a forceRuleEngine switch in the collect/valuate methods of capability-runtime.

compare / identify / generate follow LLM fallback (routing design, not a dead rule).

  • The main path for these three capabilities' Dispatcher is LLM (source=llm_router), with the rule engine as backup. Their built-in rules have been revived, but the main path does not consume them. This is a design choice, not within the scope of this fix.

Final quantification (all capabilities after fix)

CapabilityScope Rules AliveReal Object Validation
inspect6 rules with cond_script=trueHTTP: 618 issues (200 instances)
optimize4 rules (JSON.stringify removed)HTTP: 4 suggestions
validate6 general + 3 Project-specific rulesHTTP: 6 real Part rules, 9 real Project rules
repairPart/Vendor closed-loop + 10 rulesHTTP: Part closed-loop, Vendor (real ID) closed-loop
collect5 rules with cond_script=trueEngine: executed=true, collect-001 hit
evaluate2 entries with cond_script=trueEngine: executed=true, evaluate-001 hit
create_postproject-001 cond_script=trueEngine alive
compare/identify/generateRule aliveMain path uses LLM (design)

Modify file

  • server/core/rule-engine.js (INSERT column in _syncBuiltinRules + 25 rules condition_script/remove JSON.stringify)
  • No new files added, temporary debug scripts have been cleaned up.

Key learnings

  • The rule engine's "single source of truth" is the JS definition in _loadBuiltinRules(), not the DB file. Any fixes must be made here + ensure the INSERT columns in _syncBuiltinRules align with the defined fields.
  • condition must be an object, not a JSON.stringify string; otherwise, .type cannot be parsed by _evaluateCondition.
  • The engine now supports condition_script taking precedence over the type branch: unsupported types can be revived using condition_script: (ctx,data)=>bool, without modifying the engine's branching logic.
  • Port being occupied by an old process can create the illusion that "code changes are made but the old process still runs": before verification, always confirm via netstat | findstr :3006 that the port belongs only to the target process.
← 返回案例列表

左帮右臂工业智能体,把刚读到的方法跑起来

微信扫小程序、打开网页版 ylxt.chat,或下载桌面客户端,三种方式任选,马上用上。

🌐 网页版 ylxt.chat 💻 桌面版下载 📞 电话咨询
左帮右臂小程序码
微信扫码,体验小程序
分享:
🤖 Try Now →
🤖
🎁