@jadermme/orus-core
Version:
ORUS Core Framework - Universal framework for 6 Pillars assessment, domain-agnostic
268 lines • 7.97 kB
JavaScript
/**
* ORUS Core - Prioritization Engine
*
* Pure functions for pillar prioritization and ranking.
* Helps users understand which pillars need attention first.
*
* @remarks
* All functions are:
* - Pure (deterministic, no side effects)
* - Domain-agnostic (work for any vertical)
* - Configurable (custom weights and strategies)
* - Well-documented with examples
*/
import { DEFAULT_PRIORITIZATION_WEIGHTS } from '../config/defaults.js';
/**
* Calculates a numeric component for status
*
* @param status - Pillar status
* @returns Normalized value (0-100)
*
* @remarks
* - critical: 100 (highest urgency)
* - attention: 60 (moderate urgency)
* - healthy: 20 (low urgency, maintenance)
*/
function statusToComponent(status) {
const statusValues = {
critical: 100,
attention: 60,
healthy: 20
};
return statusValues[status];
}
/**
* Calculates a numeric component for trend
*
* @param trend - Pillar trend (optional)
* @returns Normalized value (0-100)
*
* @remarks
* - declining: 100 (urgent, getting worse)
* - stable: 50 (neutral)
* - improving: 0 (less urgent, already getting better)
* - undefined: 50 (neutral, no trend data)
*/
function trendToComponent(trend) {
if (!trend)
return 50; // Neutral if no trend data
const trendValues = {
declining: 100,
stable: 50,
improving: 0
};
return trendValues[trend];
}
/**
* Calculates a numeric component for confidence
*
* @param confidence - Data confidence level
* @returns Normalized value (0-100)
*
* @remarks
* - low: 80 (higher priority to collect better data)
* - medium: 50 (neutral)
* - high: 20 (reliable data, lower priority to re-assess)
*/
function confidenceToComponent(confidence) {
const confidenceValues = {
low: 80,
medium: 50,
high: 20
};
return confidenceValues[confidence];
}
/**
* Calculates a numeric component from score
*
* @param score - Pillar score (0-10)
* @returns Normalized value (0-100)
*
* @remarks
* - Inverted: lower scores = higher urgency
* - 0 => 100 (highest urgency)
* - 10 => 0 (lowest urgency)
* - Linear interpolation
*/
function scoreToComponent(score) {
// Invert: 0 score = 100 urgency, 10 score = 0 urgency
return 100 - (score * 10);
}
/**
* Calculates priority score for a single pillar
*
* @param pillar - Pillar assessment
* @param weights - Prioritization weights
* @returns Priority score (0-100) and breakdown
*
* @remarks
* - Pure function: deterministic calculation
* - Higher score = higher priority
* - Components weighted and summed
*
* @example
* ```typescript
* const pillar: PillarAssessment = {
* pillarId: PillarId.PILLAR_1,
* score: 3.0,
* status: 'critical',
* mode: 'objective',
* confidence: 'high',
* trend: 'declining',
* lastUpdated: new Date(),
* dataCompleteness: 0.9
* };
*
* const result = calculatePillarPriority(pillar, DEFAULT_PRIORITIZATION_WEIGHTS);
* // result.priorityScore will be high due to critical status + declining trend
* ```
*/
export function calculatePillarPriority(pillar, weights = DEFAULT_PRIORITIZATION_WEIGHTS) {
const statusComponent = statusToComponent(pillar.status);
const scoreComponent = scoreToComponent(pillar.score);
const trendComponent = trendToComponent(pillar.trend);
const confidenceComponent = confidenceToComponent(pillar.confidence);
// Weighted sum
const priorityScore = statusComponent * weights.status +
scoreComponent * weights.score +
trendComponent * weights.trend +
confidenceComponent * weights.confidence;
return {
priorityScore: Math.round(priorityScore * 10) / 10,
breakdown: {
statusComponent,
scoreComponent,
trendComponent,
confidenceComponent
}
};
}
/**
* Prioritizes all pillars in an assessment
*
* @param params - Prioritization parameters
* @returns Prioritization result with ranked pillars
*
* @remarks
* - Pure function: deterministic ranking
* - Default strategy: worst_first (most common use case)
* - Custom weights allow vertical-specific prioritization
* - Stable sort: preserves order for equal priority scores
*
* @example
* ```typescript
* const result = prioritizePillars({
* assessment: myAssessment,
* strategy: 'worst_first',
* weights: DEFAULT_PRIORITIZATION_WEIGHTS
* });
*
* // Get top priority pillar
* const topPriority = result.ranking[0];
* console.log(`Focus on: ${topPriority.pillarId}`);
* console.log(`Priority score: ${topPriority.priorityScore}`);
*
* // Get critical pillars only
* const critical = result.ranking
* .filter(p => myAssessment.pillars[p.pillarId].status === 'critical');
* ```
*/
export function prioritizePillars(params) {
const { assessment, strategy = 'worst_first', weights = DEFAULT_PRIORITIZATION_WEIGHTS } = params;
// Calculate priority for each pillar
const priorities = Object.values(assessment.pillars).map((pillar) => {
const { priorityScore, breakdown } = calculatePillarPriority(pillar, weights);
return {
pillarId: pillar.pillarId,
priorityScore,
rank: 0, // Will be set after sorting
breakdown
};
});
// Sort based on strategy
let sorted;
switch (strategy) {
case 'worst_first':
// Higher priority score first (most urgent)
sorted = priorities.sort((a, b) => b.priorityScore - a.priorityScore);
break;
case 'best_first':
// Lower priority score first (optimize the best)
sorted = priorities.sort((a, b) => a.priorityScore - b.priorityScore);
break;
case 'impact_first':
// Prioritize by trend + status combination
// Declining critical pillars get highest priority
sorted = priorities.sort((a, b) => {
const aImpact = a.breakdown.statusComponent * 0.6 + a.breakdown.trendComponent * 0.4;
const bImpact = b.breakdown.statusComponent * 0.6 + b.breakdown.trendComponent * 0.4;
return bImpact - aImpact;
});
break;
default:
sorted = priorities;
}
// Assign ranks (1-based)
sorted.forEach((priority, index) => {
priority.rank = index + 1;
});
return {
strategy,
ranking: sorted,
weights,
timestamp: new Date()
};
}
/**
* Gets the top N priority pillars
*
* @param result - Prioritization result
* @param count - Number of top pillars to return
* @returns Top N pillar priorities
*
* @remarks
* - Pure function: simple array slice
* - Useful for UI display ("Top 3 priorities")
* - Returns empty array if count <= 0
*
* @example
* ```typescript
* const result = prioritizePillars({ assessment });
* const top3 = getTopPriorities(result, 3);
*
* top3.forEach(p => {
* console.log(`${p.rank}. ${p.pillarId} (${p.priorityScore})`);
* });
* ```
*/
export function getTopPriorities(result, count) {
if (count <= 0)
return [];
return result.ranking.slice(0, count);
}
/**
* Gets pillars that need immediate attention
*
* @param result - Prioritization result
* @param threshold - Priority score threshold (default: 70)
* @returns Pillars above threshold
*
* @remarks
* - Pure function: simple filter
* - Default threshold 70 = urgent attention needed
* - Empty array if no pillars meet criteria
*
* @example
* ```typescript
* const result = prioritizePillars({ assessment });
* const urgent = getUrgentPillars(result, 75);
*
* if (urgent.length > 0) {
* console.log(`${urgent.length} pillars need urgent attention!`);
* }
* ```
*/
export function getUrgentPillars(result, threshold = 70) {
return result.ranking.filter((p) => p.priorityScore >= threshold);
}
//# sourceMappingURL=prioritization.js.map