Reference implementation for the Phoenix Architecture. Work in progress. aicoding.leaflet.pub/
ai coding crazy
at main 96 lines 2.9 kB view raw
1/** 2 * Compaction Engine — moves cold data to archives while preserving 3 * node headers, provenance edges, approvals, and signatures. 4 */ 5 6import type { CompactionEvent } from './models/pipeline.js'; 7 8export interface StorageStats { 9 total_objects: number; 10 total_bytes: number; 11 hot_objects: number; 12 hot_bytes: number; 13 cold_objects: number; 14 cold_bytes: number; 15} 16 17export interface CompactionCandidate { 18 object_id: string; 19 object_type: string; 20 age_days: number; 21 size_bytes: number; 22 /** Whether this object must be preserved (header, provenance, approval, sig) */ 23 preserve: boolean; 24} 25 26/** 27 * Identify objects eligible for compaction. 28 */ 29export function identifyCandidates( 30 objects: CompactionCandidate[], 31 hotWindowDays: number = 30, 32): { toCompact: CompactionCandidate[]; toPreserve: CompactionCandidate[] } { 33 const toCompact: CompactionCandidate[] = []; 34 const toPreserve: CompactionCandidate[] = []; 35 36 for (const obj of objects) { 37 if (obj.preserve) { 38 toPreserve.push(obj); 39 } else if (obj.age_days > hotWindowDays) { 40 toCompact.push(obj); 41 } else { 42 toPreserve.push(obj); 43 } 44 } 45 46 return { toCompact, toPreserve }; 47} 48 49/** 50 * Simulate a compaction run and produce an event. 51 */ 52export function runCompaction( 53 objects: CompactionCandidate[], 54 trigger: CompactionEvent['trigger'], 55 hotWindowDays: number = 30, 56): CompactionEvent { 57 const { toCompact, toPreserve } = identifyCandidates(objects, hotWindowDays); 58 59 const bytesFreed = toCompact.reduce((sum, o) => sum + o.size_bytes, 0); 60 const preservedHeaders = toPreserve.filter(o => o.object_type === 'node_header').length; 61 const preservedProvenance = toPreserve.filter(o => o.object_type === 'provenance_edge').length; 62 const preservedApprovals = toPreserve.filter(o => o.object_type === 'approval').length; 63 const preservedSignatures = toPreserve.filter(o => o.object_type === 'signature').length; 64 65 return { 66 type: 'CompactionEvent', 67 timestamp: new Date().toISOString(), 68 trigger, 69 nodes_compacted: toCompact.length, 70 bytes_freed: bytesFreed, 71 preserved: { 72 node_headers: preservedHeaders, 73 provenance_edges: preservedProvenance, 74 approvals: preservedApprovals, 75 signatures: preservedSignatures, 76 }, 77 }; 78} 79 80/** 81 * Check if compaction should be triggered. 82 */ 83export function shouldTriggerCompaction( 84 stats: StorageStats, 85 sizeThresholdBytes: number = 100 * 1024 * 1024, // 100MB default 86 daysSinceLastCompaction: number = 0, 87 timeThresholdDays: number = 90, 88): { trigger: boolean; reason: CompactionEvent['trigger'] | null } { 89 if (stats.total_bytes > sizeThresholdBytes) { 90 return { trigger: true, reason: 'size_threshold' }; 91 } 92 if (daysSinceLastCompaction > timeThresholdDays) { 93 return { trigger: true, reason: 'time_based' }; 94 } 95 return { trigger: false, reason: null }; 96}