@jadermme/orus-core
Version:
ORUS Core Framework - Universal framework for 6 Pillars assessment, domain-agnostic
264 lines • 8.63 kB
JavaScript
/**
* ORUS Core - Mode Logic
*
* Pure functions for handling assessment mode transitions and hybrid calculations.
*
* @remarks
* ORUS supports 3 assessment modes:
* - subjective: Quick user perception (low confidence)
* - objective: Data-driven via domain engines (high confidence)
* - hybrid: Combines both (medium confidence)
*
* This module provides:
* - Hybrid score resolution (combining subjective + objective)
* - Mode transition validation
* - Confidence inference from mode
*/
/**
* Resolves a hybrid score from subjective and objective inputs
*
* @param params - Hybrid score parameters
* @returns Hybrid score result with breakdown
*
* @remarks
* - Pure function: deterministic calculation
* - Default strategy: objective_priority (70/30)
* - Detects significant discrepancies (> 2 points difference)
* - Discrepancies may indicate:
* - User perception doesn't match data reality
* - Missing context in objective calculation
* - Need for user education or data review
*
* @example
* ```typescript
* const result = resolveHybridScore({
* subjectiveScore: 4.0, // User feels it's bad
* objectiveScore: 7.5, // But data shows it's good
* strategy: 'objective_priority'
* });
*
* // result.hybridScore = 6.55 (weighted toward objective)
* // result.discrepancy = 3.5
* // result.hasSignificantDiscrepancy = true
* ```
*/
export function resolveHybridScore(params) {
const { subjectiveScore, objectiveScore, strategy = 'objective_priority', customWeights } = params;
// Determine weights based on strategy
let weights;
switch (strategy) {
case 'objective_priority':
weights = { objective: 0.7, subjective: 0.3 };
break;
case 'balanced':
weights = { objective: 0.5, subjective: 0.5 };
break;
case 'subjective_priority':
weights = { objective: 0.3, subjective: 0.7 };
break;
case 'weighted':
weights = customWeights || { objective: 0.7, subjective: 0.3 };
break;
default:
weights = { objective: 0.7, subjective: 0.3 };
}
// Calculate weighted average
const hybridScore = objectiveScore * weights.objective +
subjectiveScore * weights.subjective;
// Calculate discrepancy
const discrepancy = Math.abs(objectiveScore - subjectiveScore);
const hasSignificantDiscrepancy = discrepancy > 2.0;
return {
hybridScore: Math.round(hybridScore * 10) / 10,
strategy,
weights,
discrepancy: Math.round(discrepancy * 10) / 10,
hasSignificantDiscrepancy
};
}
/**
* Infers confidence level from assessment mode
*
* @param mode - Assessment mode
* @returns Typical confidence level for that mode
*
* @remarks
* - Pure function: simple mapping
* - Default inference (can be overridden):
* - subjective => low confidence
* - objective => high confidence
* - hybrid => medium confidence
*
* @example
* ```typescript
* inferConfidenceFromMode('subjective') // => 'low'
* inferConfidenceFromMode('objective') // => 'high'
* inferConfidenceFromMode('hybrid') // => 'medium'
* ```
*/
export function inferConfidenceFromMode(mode) {
const modeToConfidence = {
subjective: 'low',
objective: 'high',
hybrid: 'medium'
};
return modeToConfidence[mode];
}
/**
* Validates if a mode transition is allowed
*
* @param transition - Mode transition to validate
* @param dataCompleteness - Current data completeness (0-1)
* @returns Validation result
*
* @remarks
* - Pure function: deterministic validation
* - Rules:
* - subjective -> objective: requires dataCompleteness >= 0.7
* - subjective -> hybrid: requires dataCompleteness >= 0.4
* - objective -> hybrid: always allowed
* - hybrid -> objective: requires dataCompleteness >= 0.8
* - Same mode: always allowed (no-op)
* - Downgrades (objective -> subjective): always allowed but warned
*
* @example
* ```typescript
* const validation = canTransitionMode(
* { from: 'subjective', to: 'objective' },
* 0.5 // Only 50% data completeness
* );
*
* // validation.isValid = false
* // validation.reason = "Insufficient data for objective mode"
* // validation.recommendations = ["Collect more data...", ...]
* ```
*/
export function canTransitionMode(transition, dataCompleteness) {
const { from, to } = transition;
// No transition needed
if (from === to) {
return {
isValid: true,
reason: 'No transition needed (same mode)'
};
}
// Subjective -> Objective
if (from === 'subjective' && to === 'objective') {
if (dataCompleteness < 0.7) {
return {
isValid: false,
reason: 'Insufficient data for objective mode (requires >= 70% completeness)',
recommendations: [
'Collect more data through domain-specific engines',
'Use hybrid mode as an intermediate step',
'Ensure all required data points are available'
]
};
}
return {
isValid: true,
reason: 'Sufficient data available for objective assessment'
};
}
// Subjective -> Hybrid
if (from === 'subjective' && to === 'hybrid') {
if (dataCompleteness < 0.4) {
return {
isValid: false,
reason: 'Insufficient data for hybrid mode (requires >= 40% completeness)',
recommendations: [
'Collect basic data points for hybrid calculation',
'Start with partial objective data and subjective input'
]
};
}
return {
isValid: true,
reason: 'Sufficient data for hybrid mode'
};
}
// Hybrid -> Objective
if (from === 'hybrid' && to === 'objective') {
if (dataCompleteness < 0.8) {
return {
isValid: false,
reason: 'Insufficient data for full objective mode (requires >= 80% completeness)',
recommendations: [
'Complete remaining data collection',
'Verify all objective metrics are available',
'Stay in hybrid mode until data is complete'
]
};
}
return {
isValid: true,
reason: 'Data completeness meets objective mode requirements'
};
}
// Objective -> Hybrid (always allowed)
if (from === 'objective' && to === 'hybrid') {
return {
isValid: true,
reason: 'Downgrade to hybrid is always allowed'
};
}
// Any -> Subjective (downgrade, allowed but warned)
if (to === 'subjective') {
return {
isValid: true,
reason: 'Downgrade to subjective mode (warning: loses data-driven insights)',
recommendations: [
'Consider if this downgrade is necessary',
'Objective/hybrid modes provide better accuracy',
'Subjective mode should be temporary'
]
};
}
// Default: allow transition
return {
isValid: true,
reason: 'Transition allowed'
};
}
/**
* Suggests optimal mode based on data completeness
*
* @param dataCompleteness - Current data completeness (0-1)
* @returns Recommended mode and reason
*
* @remarks
* - Pure function: deterministic recommendation
* - Thresholds:
* - < 0.4: subjective (insufficient data)
* - 0.4-0.7: hybrid (partial data available)
* - >= 0.7: objective (sufficient data)
*
* @example
* ```typescript
* suggestOptimalMode(0.3) // => { mode: 'subjective', ... }
* suggestOptimalMode(0.6) // => { mode: 'hybrid', ... }
* suggestOptimalMode(0.9) // => { mode: 'objective', ... }
* ```
*/
export function suggestOptimalMode(dataCompleteness) {
if (dataCompleteness < 0.4) {
return {
mode: 'subjective',
reason: 'Low data completeness - rely on user perception',
confidence: 'low'
};
}
if (dataCompleteness < 0.7) {
return {
mode: 'hybrid',
reason: 'Moderate data completeness - combine data with user input',
confidence: 'medium'
};
}
return {
mode: 'objective',
reason: 'High data completeness - rely on data-driven assessment',
confidence: 'high'
};
}
//# sourceMappingURL=modeLogic.js.map