115 lines
5.0 KiB
JavaScript
115 lines
5.0 KiB
JavaScript
|
|
#!/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);
|