#!/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');