# Gemini Fix Prompt — String Union Refactor Recovery (Final) You are a senior TypeScript systems engineer helping to fix the fallout from the failed enum → string union refactor in the **OS Self-Reflection Layer** (POINTER = OS-AWARENESS-PHASE-003). --- ## 🚨 Current Situation The previous change replaced enums with string unions (e.g. `SignalType = 'WINDOW_CHURN' | ...`), which broke all references like `SignalType.WINDOW_CHURN` and `PolicyName.THROTTLE_WINDOWS` across both `lib/reflection` and `tests/reflection`. Error example: ``` TypeError: Cannot read properties of undefined (reading 'WINDOW_CHURN') ``` Root cause: `SignalType` is now a type, not an object, so `SignalType.WINDOW_CHURN` is undefined. --- ## 🎯 Objective Perform a full recovery and stabilization refactor to restore all tests and functionality **without reverting back to enums**. You must replace every enum-style reference with a constant-based solution (`SIGNALS.WINDOW_CHURN`) or string literals. --- ## 🧩 Step-by-Step Fix Plan ### 1️⃣ Update `lib/reflection/types.ts` Replace enums with **constant objects + string union types**: ```ts // lib/reflection/types.ts // --- SIGNALS --- export const SIGNALS = { WINDOW_CHURN: 'WINDOW_CHURN', FOCUS_STABILITY: 'FOCUS_STABILITY', LATENCY_SUMMARY: 'LATENCY_SUMMARY', IDLE_RATIO: 'IDLE_RATIO', WINDOW_LIFETIME: 'WINDOW_LIFETIME', } as const; export type SignalType = typeof SIGNALS[keyof typeof SIGNALS]; // --- POLICY NAMES --- export const POLICY_NAMES = { THROTTLE_WINDOWS: 'THROTTLE_WINDOWS', DEFER_ANIMATIONS: 'DEFER_ANIMATIONS', ADJUST_PREFETCH: 'ADJUST_PREFETCH', TUNE_FOCUS_TIMEOUT: 'TUNE_FOCUS_TIMEOUT', } as const; export type PolicyName = typeof POLICY_NAMES[keyof typeof POLICY_NAMES]; export type EvalStatus = 'NORMAL' | 'WARNING' | 'CRITICAL'; export interface IntrospectionSignal { type: SignalType; value: number; timestamp: number; metadata?: Record; } export interface EvaluationResult { signal: IntrospectionSignal; status: EvalStatus; slo: { threshold: number; status: EvalStatus } | null; timestamp: number; } export interface FeedbackDecision { ts: number; cause: EvaluationResult[]; action: | 'THROTTLE_WINDOWS' | 'DEFER_ANIM' | 'ADJUST_PREFETCH' | 'TUNE_FOCUS_TIMEOUT' | 'NOOP'; params?: Record; mode: 'PROPOSED' | 'DRY_RUN' | 'APPLIED'; } ``` --- ### 2️⃣ Project-wide Find & Replace Replace enum-style references in all reflection source and test files. #### Replace: - `SignalType.WINDOW_CHURN` → `SIGNALS.WINDOW_CHURN` - `PolicyName.THROTTLE_WINDOWS` → `'THROTTLE_WINDOWS'` Example command (Linux/macOS): ```bash # Replace SignalType references rg -l "SignalType\.[A-Z_]+" lib tests | xargs sed -i -E "s/SignalType\.([A-Z_]+)/SIGNALS.\1/g" # Replace PolicyName references rg -l "PolicyName\.[A-Z_]+" lib tests | xargs sed -i -E "s/PolicyName\.([A-Z_]+)/POLICY_NAMES.\1/g" ``` If `ripgrep` isn’t available, use `grep -rl` instead. --- ### 3️⃣ Update `feedback.ts` Ensure the rules map uses string keys, not enums. ```ts import { SIGNALS, type SignalType, type EvaluationResult, type FeedbackDecision } from './types'; import { applyPolicyChange } from './policy'; type FeedbackRule = { action: FeedbackDecision['action']; threshold: 'CRITICAL' | 'WARNING' | 'NORMAL' }; const FEEDBACK_RULES: Record = { [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' }, }; export function makeDecision(evals: EvaluationResult[]): FeedbackDecision[] { const now = performance.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) { const now = performance.now(); if (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); } } export function _resetFeedbackForTests() { lastApplied = 0; } ``` --- ### 4️⃣ Fix Tests - Import the new constants: ```ts import { SIGNALS, POLICY_NAMES } from '@/lib/reflection/types'; ``` - Update usage: ```ts signal: { type: SIGNALS.WINDOW_CHURN, value: 5, timestamp: 0 } expect(getPolicyValue('THROTTLE_WINDOWS')).toBe(500); ``` - Fix timer mocking: ```ts beforeEach(() => vi.useFakeTimers()); afterEach(() => vi.useRealTimers()); ``` --- ### 5️⃣ Verify Import Aliases Ensure `vite.config.ts` includes: ```ts import path from 'path'; export default defineConfig({ resolve: { alias: { '@': path.resolve(__dirname, './') }, }, }); ``` Or switch to relative paths in test imports if needed. --- ### 6️⃣ Final Test Run Run: ```bash pnpm test:run ``` Expected summary: ``` ✓ 39 passed (0 failed) Coverage: Statements 65%, Branches 58%, Functions 60%, Lines 64% ``` --- ### ✅ Deliverables - Updated `types.ts`, `feedback.ts`, and all source/tests to use `SIGNALS` and `POLICY_NAMES` constants. - No remaining enum references. - All Vitest suites pass successfully. - Cooldown, DRY_RUN, and policy application confirmed working. Focus on **consistency, safety, and complete test recovery**.