QualityScorer.js•5.43 kB
export class QualityScorer {
constructor(configManager) {
this.configManager = configManager;
this.defaultWeights = {
novelty: 0.25,
generalizability: 0.25,
specificity: 0.2,
validation: 0.15,
impact: 0.15,
};
}
getWeights() {
return this.configManager.getScoringWeights() || this.defaultWeights;
}
scoreNovelty(fact) {
const { content, type, domain, tags = [] } = fact;
let score = 50;
if (tags.includes('experimental') || tags.includes('discovery')) {
score += 30;
}
if (content.includes('new approach') || content.includes('innovative')) {
score += 20;
}
if (type === 'discovery' || type === 'experimental_approach') {
score += 25;
}
const contentLength = content.length;
if (contentLength > 200 && contentLength < 1000) {
score += 10;
}
return Math.min(100, score);
}
scoreGeneralizability(fact) {
const { content, domain, tags = [], context = {} } = fact;
let score = 40;
const generalTerms = [
'pattern', 'principle', 'best practice', 'approach',
'strategy', 'methodology', 'framework', 'architecture'
];
const generalCount = generalTerms.filter(term =>
content.toLowerCase().includes(term)
).length;
score += generalCount * 15;
if (domain === 'general' || !domain) {
score += 20;
}
if (tags.includes('cross-platform') || tags.includes('universal')) {
score += 25;
}
const techSpecific = Object.keys(context).length;
if (techSpecific > 3) {
score -= 20;
}
return Math.min(100, score);
}
scoreSpecificity(fact) {
const { content, type, context = {}, tags = [] } = fact;
let score = 30;
const actionableTerms = [
'use', 'avoid', 'implement', 'configure', 'set',
'add', 'remove', 'replace', 'install', 'run'
];
const actionableCount = actionableTerms.filter(term =>
content.toLowerCase().includes(term)
).length;
score += actionableCount * 10;
if (content.includes('```') || content.includes('code')) {
score += 25;
}
if (type === 'verified_pattern' || type === 'debugging_solution') {
score += 20;
}
if (tags.includes('actionable') || tags.includes('step-by-step')) {
score += 15;
}
const contextDetails = Object.keys(context).length;
score += contextDetails * 5;
return Math.min(100, score);
}
scoreValidation(fact) {
const { content, type, tags = [], context = {} } = fact;
let score = 40;
if (type === 'verified_pattern' || type === 'debugging_solution') {
score += 30;
}
if (tags.includes('tested') || tags.includes('verified')) {
score += 25;
}
if (content.includes('tested') || content.includes('works') ||
content.includes('confirmed')) {
score += 20;
}
if (context.validation && context.validation === 'tested') {
score += 15;
}
if (type === 'anti_pattern') {
score += 20;
}
return Math.min(100, score);
}
scoreImpact(fact) {
const { content, type, domain, tags = [] } = fact;
let score = 35;
const impactTerms = [
'performance', 'optimization', 'security', 'scalability',
'maintainability', 'reliability', 'efficiency'
];
const impactCount = impactTerms.filter(term =>
content.toLowerCase().includes(term)
).length;
score += impactCount * 15;
if (type === 'optimization' || type === 'anti_pattern') {
score += 25;
}
if (tags.includes('critical') || tags.includes('high-impact')) {
score += 30;
}
const urgencyTerms = ['urgent', 'critical', 'important', 'breaking'];
const hasUrgency = urgencyTerms.some(term =>
content.toLowerCase().includes(term)
);
if (hasUrgency) {
score += 20;
}
return Math.min(100, score);
}
calculateQualityScore(fact) {
const weights = this.getWeights();
const scores = {
novelty: this.scoreNovelty(fact),
generalizability: this.scoreGeneralizability(fact),
specificity: this.scoreSpecificity(fact),
validation: this.scoreValidation(fact),
impact: this.scoreImpact(fact),
};
const weightedScore = Object.entries(scores).reduce(
(total, [dimension, score]) => {
return total + (score * weights[dimension]);
},
0
);
const factTypeMultiplier = this.getFactTypeMultiplier(fact.type);
const finalScore = Math.round(weightedScore * factTypeMultiplier);
return {
totalScore: Math.min(100, finalScore),
dimensionScores: scores,
weights,
factTypeMultiplier,
};
}
getFactTypeMultiplier(type) {
const multipliers = {
verified_pattern: 1.2,
anti_pattern: 1.15,
optimization: 1.1,
debugging_solution: 1.1,
discovery: 1.05,
constraint: 1.0,
tool_configuration: 0.95,
decision_rationale: 0.9,
experimental_approach: 0.85,
workflow_improvement: 1.0,
};
return multipliers[type] || 1.0;
}
meetsQualityThreshold(fact, threshold = 60) {
const result = this.calculateQualityScore(fact);
return result.totalScore >= threshold;
}
}