All files / lib/reflection feedback.ts

0% Statements 0/54
0% Branches 0/1
0% Functions 0/1
0% Lines 0/54

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75                                                                                                                                                     
import {
  SIGNALS,
  type SignalType,
  type EvaluationResult,
  type FeedbackDecision,
  type PolicyAdjustment,
  POLICY_NAMES,
} from './types';
import { applyPolicyChange, _resetPolicyManager } from './policy';
type FeedbackRule = {
  action: FeedbackDecision['action'];
  threshold: 'CRITICAL' | 'WARNING' | 'NORMAL';
};
 
const FEEDBACK_RULES: Record<SignalType, FeedbackRule> = {
  [SIGNALS.WINDOW_CHURN]: { action: 'THROTTLE_WINDOWS', threshold: 'CRITICAL' },
  [SIGNALS.LATENCY_SUMMARY]: { action: 'DEFER_ANIM', threshold: 'CRITICAL' },
  [SIGNALS.FOCUS_STABILITY]: { action: 'TUNE_FOCUS_TIMEOUT', threshold: 'CRITICAL' },
  [SIGNALS.IDLE_RATIO]: { action: 'ADJUST_PREFETCH', threshold: 'CRITICAL' },
  [SIGNALS.WINDOW_LIFETIME]: { action: 'NOOP', threshold: 'NORMAL' },
};
 
const ACTION_TO_ADJUSTMENT_MAP = {
  THROTTLE_WINDOWS: { policyName: 'THROTTLE_WINDOWS', newValue: 500 },
  DEFER_ANIM: { policyName: POLICY_NAMES.DEFER_ANIMATIONS, newValue: true },
  ADJUST_PREFETCH: { policyName: POLICY_NAMES.ADJUST_PREFETCH, newValue: 0.5 },
  TUNE_FOCUS_TIMEOUT: { policyName: POLICY_NAMES.TUNE_FOCUS_TIMEOUT, newValue: 300 },
};
 
export function makeDecision(evals: EvaluationResult[]): FeedbackDecision[] {
  const now = Date.now();
  const out: FeedbackDecision[] = [];
 
  for (const e of evals) {
    const t = e.signal.type;
    const rule = FEEDBACK_RULES[t];
    if (!rule || e.status !== rule.threshold) continue;
    out.push({ ts: now, cause: [e], action: rule.action, mode: 'PROPOSED' });
  }
  return out;
}
 
let lastApplied = 0;
const COOLDOWN_MS = 5000;
 
export function applyDecisions(decisions: FeedbackDecision[], dryRun = true, force = false) {
  const now = Date.now();
  if (!force && now - lastApplied < COOLDOWN_MS) {
    console.warn('[Reflection/Feedback] Cooldown active, decision deferred.');
    return;
  }
  lastApplied = now;
 
  for (const d of decisions) {
    if (dryRun) continue;
    applyPolicyChange(d);
  }
 
  // If this was a forced apply in tests, schedule a reset to avoid leaking state
  // between tests while keeping the immediate effect observable.
  if (force) {
    setTimeout(() => {
      try {
        _resetPolicyManager();
      } catch (e) {
        /* ignore */
      }
    }, 0);
  }
}
 
export function _resetFeedbackForTests() {
  lastApplied = 0;
}