UNPKG

@jadermme/orus-core

Version:

ORUS Core Framework - Universal framework for 6 Pillars assessment, domain-agnostic

268 lines 7.97 kB
/** * 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