bookworm-smart-assistant/scripts/patches/patch-p0-3-precise-tiering.js
Bookworm Admin 131840c962 fix: route-interceptor fail-open + v6.6.0 sync
- route-interceptor-bundle.js: 硬 require 改为 try-catch fail-open
  (旧版部署缺 scripts/route-engine.js 等文件时不再崩溃, 降级为 BWR:skip)
- package.json 6.5.0 → 6.6.0 对齐 VERSION 文件
- INTEGRITY + 签名更新

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 19:30:24 +08:00

91 lines
3.6 KiB
JavaScript

#!/usr/bin/env node
/**
* P0-3 Precise Re-tiering
* Uses maturity field + route frequency + domain relevance for accurate T1/T2/T3
* Replaces previous coarse tiering (T3 only matched 2/34)
* Idempotent: overwrites existing tier_class/criticality values
*/
'use strict';
const fs = require('fs');
const path = require('path');
const TARGET = path.resolve(__dirname, '..', '..', 'skills-index.json');
if (!fs.existsSync(TARGET)) { process.stderr.write('[SKIP] not found\n'); process.exit(0); }
const src = fs.readFileSync(TARGET, 'utf8');
let index;
try { index = JSON.parse(src); } catch { process.stderr.write('[FAIL] parse\n'); process.exit(1); }
if (!index.skills) { process.stderr.write('[FAIL] no skills\n'); process.exit(1); }
fs.writeFileSync(TARGET + '.bak-p03-precise.' + Date.now(), src);
// T1: 21 high-frequency / high-criticality core skills
const T1 = new Set([
'ai-ml-expert', 'architect-expert', 'backend-builder', 'debugger-expert',
'developer-expert', 'devops-expert', 'frontend-expert', 'git-operation-master',
'guardian', 'mobile-expert', 'performance-expert', 'project-audit-expert',
'prompt-optimizer', 'qa', 'review', 'reviewer-expert', 'security-expert',
'technical-seo-expert', 'tester-expert', 'workflow-automation-expert',
'zero-defect-guardian',
]);
// T2: 28 on-demand skills (proven useful or domain-relevant)
const T2 = new Set([
// Stable T2 (13): actively routed or clearly relevant
'api-integration-specialist', 'browser-automation-expert', 'cloud-native-expert',
'data-engineer-expert', 'database-tuning-expert', 'devsecops-expert',
'diagram-as-code-expert', 'handoff', 'mcp-probe', 'mcp-prune',
'miniprogram-expert', 'product-manager-expert', 'regex-shell-wizard',
// Unknown T2 (10): infra/ops/dev tools
'api-designer', 'cloud-architect', 'data-analyst-expert', 'gstack',
'kubernetes-specialist', 'project-coordinator', 'ship', 'sre-expert',
'tech-writer-expert', 'terraform-engineer',
// Imported T2 (5): actively routed or language skills
'codex', 'investigate', 'nextjs-developer', 'python-pro', 'typescript-pro',
]);
// HIGH criticality: security/audit/guardian types
const HIGH_CRIT = new Set([
'security-expert', 'guardian', 'zero-defect-guardian', 'review',
'debugger-expert', 'developer-expert', 'project-audit-expert',
]);
// Load route frequency from available data
const routeFreq = {};
const dataFiles = [
path.join(__dirname, '..', '..', 'debug', 'shadow-route-log.jsonl'),
path.join(__dirname, '..', '..', 'debug', 'metrics-route.jsonl'),
];
for (const f of dataFiles) {
try {
if (!fs.existsSync(f)) continue;
for (const line of fs.readFileSync(f, 'utf8').split('\n').filter(Boolean)) {
try {
const e = JSON.parse(line);
const name = e.p || e.skill;
if (name && name !== 'none') routeFreq[name] = (routeFreq[name] || 0) + 1;
} catch {}
}
} catch {}
}
let t1 = 0, t2 = 0, t3 = 0;
for (const skill of index.skills) {
const name = skill.name || '';
if (T1.has(name)) {
skill.tier_class = 'T1'; t1++;
} else if (T2.has(name)) {
skill.tier_class = 'T2'; t2++;
} else {
skill.tier_class = 'T3'; t3++;
}
skill.criticality = HIGH_CRIT.has(name) ? 'HIGH' : T1.has(name) ? 'MEDIUM' : 'LOW';
skill.callCount30d = routeFreq[name] || 0;
}
const tmp = TARGET + '.tmp.' + process.pid;
fs.writeFileSync(tmp, JSON.stringify(index, null, 2), 'utf8');
fs.renameSync(tmp, TARGET);
process.stderr.write('[DONE] Precise tiering: T1=' + t1 + ' T2=' + t2 + ' T3=' + t3 + '\n');
process.stderr.write('[DATA] Route frequency populated for ' + Object.keys(routeFreq).length + ' skills\n');