#!/usr/bin/env node /** * patch-route-precision-10x-batch-b3.js * 路由精度10项改进 — Batch B3: fusion-weight-learner 激活诊断 + CLAUDE.md 规则数更新 * Item 6: fusion-weight-learner 激活状态核查 * 诊断结论: learner 已在 stop-dispatcher.js Batch2 中被调用 (race 'implicit→fwl') * fusion-weights.json 中 corrections=0 是 bootstrap 元数据,不代表 learner 未运行 * root cause: 所有 route-feedback.jsonl 条目均为 routedTo===correctedTo (timeout-confirm) * 修复: 在 learner 跳过时写入诊断日志,便于后续追踪 * CLAUDE.md: 将 "89条" 更新为实际规则数 * * 安全性: .bak 备份 + sentinel 检查 + UTF-8 无 BOM 写入 */ 'use strict'; const fs = require('fs'); const path = require('path'); const CLAUDE_ROOT = path.join(require('os').homedir(), '.claude'); const SCRIPTS_DIR = path.join(CLAUDE_ROOT, 'scripts'); const HOOKS_DIR = path.join(CLAUDE_ROOT, 'hooks'); const DEBUG_DIR = path.join(CLAUDE_ROOT, 'debug'); const CLAUDE_MD = path.join(CLAUDE_ROOT, 'CLAUDE.md'); const RULES_FILE = path.join(SCRIPTS_DIR, 'disambiguation-rules.json'); // ── Item 6: 核查 fusion-weight-learner 调用链 ────────────────── console.log('\n[ITEM6] Verifying fusion-weight-learner activation chain...'); // 1. 检查 stop-dispatcher.js 是否调用了 fusion-weight-learner const STOP_DISPATCHER = path.join(HOOKS_DIR, 'stop-dispatcher.js'); let item6Status = 'UNKNOWN'; let item6Detail = ''; if (fs.existsSync(STOP_DISPATCHER)) { const sdSrc = fs.readFileSync(STOP_DISPATCHER, 'utf8'); if (sdSrc.includes('fusion-weight-learner.js')) { item6Status = 'ALREADY_ACTIVE'; item6Detail = 'fusion-weight-learner.js is called in stop-dispatcher.js Batch2 (race "implicit→fwl")'; console.log('[ITEM6] SKIP — learner already wired in stop-dispatcher.js'); console.log('[ITEM6] Root cause of corrections=0: all route-feedback.jsonl entries have routedTo===correctedTo'); console.log('[ITEM6] Learner runs but returns {status:"skip", reason:"纠正不足2条"} — this is correct behavior'); console.log('[ITEM6] No code change needed. Writing diagnostic note to debug log.'); } else { item6Status = 'NOT_WIRED'; item6Detail = 'fusion-weight-learner.js NOT found in stop-dispatcher.js — needs wiring'; console.log('[ITEM6] WARN — learner not found in stop-dispatcher. Manual investigation required.'); } } else { item6Status = 'STOP_DISPATCHER_MISSING'; item6Detail = 'stop-dispatcher.js not found'; console.log('[ITEM6] ERROR — stop-dispatcher.js not found at', STOP_DISPATCHER); } // 2. 写入诊断日志 try { if (!fs.existsSync(DEBUG_DIR)) fs.mkdirSync(DEBUG_DIR, { recursive: true }); const diagEntry = JSON.stringify({ ts: new Date().toISOString(), event: 'fusion-weight-learner-audit', status: item6Status, detail: item6Detail, fusionWeightsFile: path.join(DEBUG_DIR, 'fusion-weights.json'), action: item6Status === 'ALREADY_ACTIVE' ? 'no-change-needed' : 'manual-review-required', }) + '\n'; fs.appendFileSync(path.join(DEBUG_DIR, 'route-engine-audit.log'), diagEntry); console.log('[ITEM6] Diagnostic written to debug/route-engine-audit.log'); } catch (e) { console.error('[ITEM6] Could not write diagnostic log:', e.message); } // ── CLAUDE.md 规则数更新 ────────────────────────────────────── console.log('\n[CLAUDE.MD] Updating disambiguation rule count...'); if (!fs.existsSync(CLAUDE_MD)) { console.error('[CLAUDE.MD] CLAUDE.md not found:', CLAUDE_MD); } else { // 读取实际规则数 let actualRuleCount = null; try { const rules = JSON.parse(fs.readFileSync(RULES_FILE, 'utf8')); actualRuleCount = rules.rules ? rules.rules.length : null; } catch (e) { console.error('[CLAUDE.MD] Could not read rules file:', e.message); } if (actualRuleCount !== null) { const mdSrc = fs.readFileSync(CLAUDE_MD, 'utf8'); const BAK_MD = CLAUDE_MD + '.bak'; // 查找并替换规则数引用 (格式: "完整 N 条见 scripts/disambiguation-rules.json") const ruleRefPattern = /完整\s+\d+\s*条见\s+scripts\/disambiguation-rules\.json/g; const matches = mdSrc.match(ruleRefPattern); if (!matches) { console.log('[CLAUDE.MD] No rule count reference found matching pattern. Skipping.'); } else { fs.writeFileSync(BAK_MD, mdSrc, 'utf8'); const patched = mdSrc.replace( ruleRefPattern, `完整 ${actualRuleCount} 条见 scripts/disambiguation-rules.json` ); if (patched === mdSrc) { console.log('[CLAUDE.MD] Content unchanged (already up to date).'); } else { fs.writeFileSync(CLAUDE_MD, patched, 'utf8'); console.log(`[CLAUDE.MD] Updated rule count to ${actualRuleCount} (was: ${matches[0]})`); } } } } console.log('\n[DONE] Batch B3 complete.'); console.log(' Item 6 status:', item6Status);