@sovr/engine 3.4.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -22,16 +22,26 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AdaptiveThresholdManager: () => AdaptiveThresholdManager,
24
24
  AutoHardenEngine: () => AutoHardenEngine,
25
+ ContextAccelerator: () => ContextAccelerator,
25
26
  CostGateEnhancedEngine: () => CostGateEnhancedEngine,
27
+ DEFAULT_CA_CONFIG: () => DEFAULT_CA_CONFIG,
28
+ DEFAULT_GE_CONFIG: () => DEFAULT_GE_CONFIG,
29
+ DEFAULT_HARD_RULES: () => DEFAULT_HARD_RULES,
26
30
  DEFAULT_RULES: () => DEFAULT_RULES,
31
+ DEFAULT_SCORING_WEIGHTS: () => DEFAULT_SCORING_WEIGHTS,
32
+ DEFAULT_TSA_CONFIG: () => DEFAULT_TSA_CONFIG,
27
33
  EvolutionChannelEngine: () => EvolutionChannelEngine,
28
34
  FeatureSwitchesManager: () => FeatureSwitchesManager,
35
+ GovernanceEnhancer: () => GovernanceEnhancer,
29
36
  MultiLevelBudgetEngine: () => MultiLevelBudgetEngine,
30
37
  PolicyEngine: () => PolicyEngine,
31
38
  PricingRulesEngine: () => PricingRulesEngine,
32
39
  RecalculationEngine: () => RecalculationEngine,
33
40
  SOVR_FEATURE_SWITCHES: () => SOVR_FEATURE_SWITCHES,
34
41
  SemanticDriftDetectorEngine: () => SemanticDriftDetectorEngine,
42
+ TimeSeriesAggregator: () => TimeSeriesAggregator,
43
+ TwoPhaseRouter: () => TwoPhaseRouter,
44
+ ValuationModel: () => ValuationModel,
35
45
  compileFromJSON: () => compileFromJSON,
36
46
  compileRuleSet: () => compileRuleSet,
37
47
  createAutoHardenEngine: () => createAutoHardenEngine,
@@ -2054,6 +2064,1206 @@ function createEvolutionChannel(config) {
2054
2064
  return new EvolutionChannelEngine(config);
2055
2065
  }
2056
2066
 
2067
+ // src/twoPhaseRouter.ts
2068
+ var DEFAULT_HARD_RULES = [
2069
+ {
2070
+ id: "HR-001",
2071
+ name: "high_risk_requires_powerful",
2072
+ condition: (req, candidate) => (req.riskLevel === "critical" || req.riskLevel === "high") && candidate.tier === "cheap",
2073
+ reasonCode: "RISK_TIER_MISMATCH",
2074
+ reasonTemplate: "High/critical risk tasks cannot use cheap tier models",
2075
+ enabled: true
2076
+ },
2077
+ {
2078
+ id: "HR-002",
2079
+ name: "critical_requires_powerful_only",
2080
+ condition: (req, candidate) => req.riskLevel === "critical" && candidate.tier !== "powerful",
2081
+ reasonCode: "RISK_TIER_MISMATCH",
2082
+ reasonTemplate: "Critical risk tasks require powerful tier models only",
2083
+ enabled: true
2084
+ },
2085
+ {
2086
+ id: "HR-003",
2087
+ name: "budget_hard_cap",
2088
+ condition: (req, candidate) => {
2089
+ if (!req.maxCostUsd) return false;
2090
+ const estimatedCost = req.estimatedTokens / 1e3 * candidate.costPer1kTokens;
2091
+ return estimatedCost > req.maxCostUsd;
2092
+ },
2093
+ reasonCode: "COST_EXCEEDS_BUDGET",
2094
+ reasonTemplate: "Estimated cost exceeds hard budget cap",
2095
+ enabled: true
2096
+ }
2097
+ ];
2098
+ var DEFAULT_SCORING_WEIGHTS = {
2099
+ cost: 0.25,
2100
+ latency: 0.2,
2101
+ capability: 0.25,
2102
+ weight: 0.15,
2103
+ tierMatch: 0.15
2104
+ };
2105
+ var TwoPhaseRouter = class {
2106
+ config;
2107
+ constructor(config) {
2108
+ this.config = {
2109
+ ...config,
2110
+ hardRules: config.hardRules.length > 0 ? config.hardRules : DEFAULT_HARD_RULES,
2111
+ scoringWeights: config.scoringWeights ?? DEFAULT_SCORING_WEIGHTS
2112
+ };
2113
+ }
2114
+ /**
2115
+ * Phase 1: Eligibility — 硬性规则过滤
2116
+ */
2117
+ evaluateEligibility(request) {
2118
+ return this.config.models.map((candidate) => {
2119
+ if (!candidate.enabled) {
2120
+ return {
2121
+ candidateId: candidate.id,
2122
+ eligible: false,
2123
+ reasonCode: "DISABLED",
2124
+ reasonDetail: `Model ${candidate.name} is disabled`
2125
+ };
2126
+ }
2127
+ const missingCaps = request.requiredCapabilities.filter(
2128
+ (cap) => !candidate.capabilities.includes(cap)
2129
+ );
2130
+ if (missingCaps.length > 0) {
2131
+ return {
2132
+ candidateId: candidate.id,
2133
+ eligible: false,
2134
+ reasonCode: "CAPABILITY_MISSING",
2135
+ reasonDetail: `Missing capabilities: ${missingCaps.join(", ")}`
2136
+ };
2137
+ }
2138
+ if (request.estimatedTokens > candidate.maxContextTokens) {
2139
+ return {
2140
+ candidateId: candidate.id,
2141
+ eligible: false,
2142
+ reasonCode: "CONTEXT_TOO_LARGE",
2143
+ reasonDetail: `Estimated ${request.estimatedTokens} tokens exceeds max ${candidate.maxContextTokens}`
2144
+ };
2145
+ }
2146
+ if (request.maxLatencyMs && candidate.avgLatencyMs > request.maxLatencyMs) {
2147
+ return {
2148
+ candidateId: candidate.id,
2149
+ eligible: false,
2150
+ reasonCode: "LATENCY_EXCEEDS_LIMIT",
2151
+ reasonDetail: `Avg latency ${candidate.avgLatencyMs}ms exceeds limit ${request.maxLatencyMs}ms`
2152
+ };
2153
+ }
2154
+ for (const rule of this.config.hardRules) {
2155
+ if (!rule.enabled) continue;
2156
+ if (rule.condition(request, candidate)) {
2157
+ return {
2158
+ candidateId: candidate.id,
2159
+ eligible: false,
2160
+ reasonCode: rule.reasonCode,
2161
+ reasonDetail: rule.reasonTemplate
2162
+ };
2163
+ }
2164
+ }
2165
+ return {
2166
+ candidateId: candidate.id,
2167
+ eligible: true,
2168
+ reasonCode: "ELIGIBLE",
2169
+ reasonDetail: "Passed all eligibility checks"
2170
+ };
2171
+ });
2172
+ }
2173
+ /**
2174
+ * Phase 2: Scoring — 软性指标加权评分
2175
+ */
2176
+ evaluateScoring(request, eligibleIds) {
2177
+ const eligible = this.config.models.filter((m) => eligibleIds.has(m.id));
2178
+ if (eligible.length === 0) return [];
2179
+ const w = this.config.scoringWeights;
2180
+ const maxCost = Math.max(...eligible.map((m) => m.costPer1kTokens), 1e-3);
2181
+ const maxLatency = Math.max(...eligible.map((m) => m.avgLatencyMs), 1);
2182
+ return eligible.map((candidate) => {
2183
+ const costScore = 100 * (1 - candidate.costPer1kTokens / maxCost);
2184
+ const latencyScore = 100 * (1 - candidate.avgLatencyMs / maxLatency);
2185
+ const matchedCaps = request.requiredCapabilities.filter(
2186
+ (cap) => candidate.capabilities.includes(cap)
2187
+ ).length;
2188
+ const capabilityScore = request.requiredCapabilities.length > 0 ? 100 * (matchedCaps / request.requiredCapabilities.length) : 50;
2189
+ const weightScore = candidate.weight;
2190
+ let tierMatchScore = 50;
2191
+ if (request.preferredTier) {
2192
+ if (candidate.tier === request.preferredTier) tierMatchScore = 100;
2193
+ else {
2194
+ const tierOrder = ["cheap", "balanced", "powerful"];
2195
+ const diff = Math.abs(
2196
+ tierOrder.indexOf(candidate.tier) - tierOrder.indexOf(request.preferredTier)
2197
+ );
2198
+ tierMatchScore = Math.max(0, 100 - diff * 40);
2199
+ }
2200
+ }
2201
+ const score = costScore * w.cost + latencyScore * w.latency + capabilityScore * w.capability + weightScore * w.weight + tierMatchScore * w.tierMatch;
2202
+ return {
2203
+ candidateId: candidate.id,
2204
+ score: Math.round(score * 100) / 100,
2205
+ breakdown: {
2206
+ costScore: Math.round(costScore * 100) / 100,
2207
+ latencyScore: Math.round(latencyScore * 100) / 100,
2208
+ capabilityScore: Math.round(capabilityScore * 100) / 100,
2209
+ weightScore: Math.round(weightScore * 100) / 100,
2210
+ tierMatchScore: Math.round(tierMatchScore * 100) / 100
2211
+ }
2212
+ };
2213
+ });
2214
+ }
2215
+ /**
2216
+ * Main routing decision
2217
+ */
2218
+ async route(request) {
2219
+ const startTime = Date.now();
2220
+ const phase1Results = this.evaluateEligibility(request);
2221
+ const eligibleIds = new Set(
2222
+ phase1Results.filter((r) => r.eligible).map((r) => r.candidateId)
2223
+ );
2224
+ const phase2Results = this.evaluateScoring(request, eligibleIds);
2225
+ phase2Results.sort((a, b) => b.score - a.score);
2226
+ let selectedModelId;
2227
+ let fallbackUsed = false;
2228
+ const reasonChain = [];
2229
+ if (phase2Results.length > 0) {
2230
+ selectedModelId = phase2Results[0].candidateId;
2231
+ reasonChain.push(
2232
+ `Phase 1: ${eligibleIds.size}/${this.config.models.length} candidates eligible`
2233
+ );
2234
+ reasonChain.push(
2235
+ `Phase 2: Top scorer = ${selectedModelId} (score: ${phase2Results[0].score})`
2236
+ );
2237
+ const rejected = phase1Results.filter((r) => !r.eligible);
2238
+ if (rejected.length > 0) {
2239
+ reasonChain.push(
2240
+ `Rejected: ${rejected.map((r) => `${r.candidateId}(${r.reasonCode})`).join(", ")}`
2241
+ );
2242
+ }
2243
+ } else if (this.config.fallbackModelId) {
2244
+ selectedModelId = this.config.fallbackModelId;
2245
+ fallbackUsed = true;
2246
+ reasonChain.push("Phase 1: No eligible candidates");
2247
+ reasonChain.push(`Fallback: Using ${selectedModelId}`);
2248
+ } else {
2249
+ const leastBad = this.config.models.find((m) => m.enabled);
2250
+ selectedModelId = leastBad?.id ?? this.config.models[0]?.id ?? "unknown";
2251
+ fallbackUsed = true;
2252
+ reasonChain.push("Phase 1: No eligible candidates, no fallback configured");
2253
+ reasonChain.push(`Emergency: Using ${selectedModelId}`);
2254
+ }
2255
+ const selectedModel = this.config.models.find((m) => m.id === selectedModelId);
2256
+ const decisionTimeMs = Date.now() - startTime;
2257
+ const decision = {
2258
+ selectedModelId,
2259
+ selectedModelName: selectedModel?.name ?? "unknown",
2260
+ tier: selectedModel?.tier ?? this.config.defaultTier,
2261
+ phase1Results,
2262
+ phase2Results,
2263
+ reasonChain,
2264
+ totalCandidates: this.config.models.length,
2265
+ eligibleCandidates: eligibleIds.size,
2266
+ decisionTimeMs,
2267
+ fallbackUsed
2268
+ };
2269
+ if (this.config.onDecision) {
2270
+ try {
2271
+ await this.config.onDecision(decision);
2272
+ } catch {
2273
+ }
2274
+ }
2275
+ if (this.config.onAudit) {
2276
+ try {
2277
+ await this.config.onAudit({
2278
+ type: "routing_decision",
2279
+ data: {
2280
+ selectedModelId,
2281
+ tier: decision.tier,
2282
+ eligibleCount: eligibleIds.size,
2283
+ totalCount: this.config.models.length,
2284
+ fallbackUsed,
2285
+ decisionTimeMs,
2286
+ taskType: request.taskType,
2287
+ riskLevel: request.riskLevel
2288
+ }
2289
+ });
2290
+ } catch {
2291
+ }
2292
+ }
2293
+ return decision;
2294
+ }
2295
+ /**
2296
+ * Get models by tier
2297
+ */
2298
+ getModelsByTier(tier) {
2299
+ return this.config.models.filter((m) => m.tier === tier && m.enabled);
2300
+ }
2301
+ /**
2302
+ * Update model status
2303
+ */
2304
+ updateModel(modelId, updates) {
2305
+ const idx = this.config.models.findIndex((m) => m.id === modelId);
2306
+ if (idx === -1) return false;
2307
+ this.config.models[idx] = { ...this.config.models[idx], ...updates };
2308
+ return true;
2309
+ }
2310
+ /**
2311
+ * Add a new hard rule
2312
+ */
2313
+ addHardRule(rule) {
2314
+ this.config.hardRules.push(rule);
2315
+ }
2316
+ /**
2317
+ * Get routing explanation for a specific request (dry run)
2318
+ */
2319
+ async explain(request) {
2320
+ const decision = await this.route(request);
2321
+ const lines = [
2322
+ `=== SOVR Routing Explanation ===`,
2323
+ `Task: ${request.taskType} | Risk: ${request.riskLevel}`,
2324
+ `Required Capabilities: ${request.requiredCapabilities.join(", ") || "none"}`,
2325
+ `Estimated Tokens: ${request.estimatedTokens}`,
2326
+ ``,
2327
+ `--- Phase 1: Eligibility ---`
2328
+ ];
2329
+ for (const r of decision.phase1Results) {
2330
+ const model = this.config.models.find((m) => m.id === r.candidateId);
2331
+ lines.push(
2332
+ ` ${r.eligible ? "\u2705" : "\u274C"} ${model?.name ?? r.candidateId} [${r.reasonCode}] ${r.reasonDetail}`
2333
+ );
2334
+ }
2335
+ lines.push("", `--- Phase 2: Scoring ---`);
2336
+ for (const r of decision.phase2Results) {
2337
+ const model = this.config.models.find((m) => m.id === r.candidateId);
2338
+ lines.push(
2339
+ ` ${model?.name ?? r.candidateId}: ${r.score} (cost=${r.breakdown.costScore} lat=${r.breakdown.latencyScore} cap=${r.breakdown.capabilityScore})`
2340
+ );
2341
+ }
2342
+ lines.push(
2343
+ "",
2344
+ `--- Decision ---`,
2345
+ `Selected: ${decision.selectedModelName} (${decision.tier})`,
2346
+ `Fallback: ${decision.fallbackUsed ? "YES" : "NO"}`,
2347
+ `Time: ${decision.decisionTimeMs}ms`
2348
+ );
2349
+ return { decision, explanation: lines.join("\n") };
2350
+ }
2351
+ };
2352
+
2353
+ // src/timeSeriesAggregator.ts
2354
+ var DEFAULT_TSA_CONFIG = {
2355
+ windowSizeMs: 6e4,
2356
+ // 1 minute
2357
+ windowType: "tumbling",
2358
+ maxWindows: 60,
2359
+ // Keep 1 hour of 1-min windows
2360
+ maxValuesPerWindow: 1e4
2361
+ };
2362
+ function percentile(sorted, p) {
2363
+ if (sorted.length === 0) return 0;
2364
+ if (sorted.length === 1) return sorted[0];
2365
+ const idx = p / 100 * (sorted.length - 1);
2366
+ const lower = Math.floor(idx);
2367
+ const upper = Math.ceil(idx);
2368
+ if (lower === upper) return sorted[lower];
2369
+ return sorted[lower] + (sorted[upper] - sorted[lower]) * (idx - lower);
2370
+ }
2371
+ var TimeSeriesAggregator = class {
2372
+ windows = /* @__PURE__ */ new Map();
2373
+ closedResults = [];
2374
+ config;
2375
+ totalDedups = 0;
2376
+ constructor(config) {
2377
+ this.config = { ...DEFAULT_TSA_CONFIG, ...config };
2378
+ }
2379
+ /**
2380
+ * Ingest a data point (idempotent — duplicates are rejected)
2381
+ */
2382
+ async ingest(point) {
2383
+ const windowId = this.getWindowId(point.timestamp);
2384
+ let window = this.windows.get(windowId);
2385
+ if (!window) {
2386
+ window = this.createWindow(windowId, point.timestamp);
2387
+ this.windows.set(windowId, window);
2388
+ this.evictOldWindows();
2389
+ }
2390
+ if (window.seenIds.has(point.id)) {
2391
+ this.totalDedups++;
2392
+ return { accepted: false, windowId, duplicate: true };
2393
+ }
2394
+ window.seenIds.add(point.id);
2395
+ window.count++;
2396
+ window.sum += point.value;
2397
+ window.min = Math.min(window.min, point.value);
2398
+ window.max = Math.max(window.max, point.value);
2399
+ if (window.values.length < this.config.maxValuesPerWindow) {
2400
+ window.values.push(point.value);
2401
+ }
2402
+ return { accepted: true, windowId, duplicate: false };
2403
+ }
2404
+ /**
2405
+ * Ingest multiple points (batch)
2406
+ */
2407
+ async ingestBatch(points) {
2408
+ let accepted = 0;
2409
+ let duplicates = 0;
2410
+ let errors = 0;
2411
+ for (const point of points) {
2412
+ try {
2413
+ const result = await this.ingest(point);
2414
+ if (result.accepted) accepted++;
2415
+ if (result.duplicate) duplicates++;
2416
+ } catch {
2417
+ errors++;
2418
+ }
2419
+ }
2420
+ return { accepted, duplicates, errors };
2421
+ }
2422
+ /**
2423
+ * Get aggregation result for a specific window
2424
+ */
2425
+ getWindowResult(windowId) {
2426
+ const window = this.windows.get(windowId);
2427
+ if (!window) {
2428
+ return this.closedResults.find((r) => r.windowId === windowId) ?? null;
2429
+ }
2430
+ return this.computeResult(window);
2431
+ }
2432
+ /**
2433
+ * Get current (latest) window result
2434
+ */
2435
+ getCurrentResult() {
2436
+ const now = Date.now();
2437
+ const windowId = this.getWindowId(now);
2438
+ return this.getWindowResult(windowId);
2439
+ }
2440
+ /**
2441
+ * Get results for a time range
2442
+ */
2443
+ getResultsInRange(startMs, endMs) {
2444
+ const results = [];
2445
+ for (const window of this.windows.values()) {
2446
+ if (window.startMs >= startMs && window.endMs <= endMs) {
2447
+ results.push(this.computeResult(window));
2448
+ }
2449
+ }
2450
+ for (const result of this.closedResults) {
2451
+ if (result.startMs >= startMs && result.endMs <= endMs) {
2452
+ if (!results.find((r) => r.windowId === result.windowId)) {
2453
+ results.push(result);
2454
+ }
2455
+ }
2456
+ }
2457
+ return results.sort((a, b) => a.startMs - b.startMs);
2458
+ }
2459
+ /**
2460
+ * Close current window and emit result
2461
+ */
2462
+ async closeWindow(windowId) {
2463
+ const window = this.windows.get(windowId);
2464
+ if (!window) return null;
2465
+ const result = this.computeResult(window);
2466
+ this.closedResults.push(result);
2467
+ this.windows.delete(windowId);
2468
+ if (this.closedResults.length > this.config.maxWindows * 2) {
2469
+ this.closedResults = this.closedResults.slice(-this.config.maxWindows);
2470
+ }
2471
+ if (this.config.onWindowClosed) {
2472
+ try {
2473
+ await this.config.onWindowClosed(result);
2474
+ } catch {
2475
+ }
2476
+ }
2477
+ if (this.config.onAudit) {
2478
+ try {
2479
+ await this.config.onAudit({
2480
+ type: "window_closed",
2481
+ data: {
2482
+ windowId,
2483
+ count: result.metrics.count,
2484
+ avg: result.metrics.avg,
2485
+ p95: result.metrics.p95,
2486
+ dedupCount: result.dedupCount
2487
+ }
2488
+ });
2489
+ } catch {
2490
+ }
2491
+ }
2492
+ return result;
2493
+ }
2494
+ /**
2495
+ * Get overall stats
2496
+ */
2497
+ getStats() {
2498
+ let totalDataPoints = 0;
2499
+ for (const w of this.windows.values()) totalDataPoints += w.count;
2500
+ for (const r of this.closedResults) totalDataPoints += r.metrics.count;
2501
+ return {
2502
+ activeWindows: this.windows.size,
2503
+ closedWindows: this.closedResults.length,
2504
+ totalDedups: this.totalDedups,
2505
+ totalDataPoints
2506
+ };
2507
+ }
2508
+ /**
2509
+ * Reset all windows
2510
+ */
2511
+ reset() {
2512
+ this.windows.clear();
2513
+ this.closedResults = [];
2514
+ this.totalDedups = 0;
2515
+ }
2516
+ // ─── Internal ────────────────────────────────────────────────────
2517
+ getWindowId(timestamp) {
2518
+ const windowStart = Math.floor(timestamp / this.config.windowSizeMs) * this.config.windowSizeMs;
2519
+ return `w_${windowStart}`;
2520
+ }
2521
+ createWindow(windowId, timestamp) {
2522
+ const windowStart = Math.floor(timestamp / this.config.windowSizeMs) * this.config.windowSizeMs;
2523
+ return {
2524
+ windowId,
2525
+ windowType: this.config.windowType,
2526
+ startMs: windowStart,
2527
+ endMs: windowStart + this.config.windowSizeMs,
2528
+ count: 0,
2529
+ sum: 0,
2530
+ min: Infinity,
2531
+ max: -Infinity,
2532
+ values: [],
2533
+ seenIds: /* @__PURE__ */ new Set()
2534
+ };
2535
+ }
2536
+ computeResult(window) {
2537
+ const sorted = [...window.values].sort((a, b) => a - b);
2538
+ const durationSec = (window.endMs - window.startMs) / 1e3;
2539
+ return {
2540
+ windowId: window.windowId,
2541
+ windowType: window.windowType,
2542
+ startMs: window.startMs,
2543
+ endMs: window.endMs,
2544
+ metrics: {
2545
+ count: window.count,
2546
+ sum: window.sum,
2547
+ avg: window.count > 0 ? window.sum / window.count : 0,
2548
+ min: window.min === Infinity ? 0 : window.min,
2549
+ max: window.max === -Infinity ? 0 : window.max,
2550
+ p50: percentile(sorted, 50),
2551
+ p95: percentile(sorted, 95),
2552
+ p99: percentile(sorted, 99),
2553
+ rate: durationSec > 0 ? window.count / durationSec : 0
2554
+ },
2555
+ dedupCount: window.seenIds.size - window.count > 0 ? 0 : this.totalDedups
2556
+ };
2557
+ }
2558
+ evictOldWindows() {
2559
+ if (this.windows.size <= this.config.maxWindows) return;
2560
+ const sorted = Array.from(this.windows.entries()).sort((a, b) => a[1].startMs - b[1].startMs);
2561
+ while (sorted.length > this.config.maxWindows) {
2562
+ const [id, window] = sorted.shift();
2563
+ this.closedResults.push(this.computeResult(window));
2564
+ this.windows.delete(id);
2565
+ }
2566
+ }
2567
+ };
2568
+
2569
+ // src/valuationModel.ts
2570
+ var ValuationModel = class {
2571
+ config;
2572
+ constructor(config) {
2573
+ this.config = config ?? {};
2574
+ }
2575
+ /**
2576
+ * Calculate TAM/SAM/SOM
2577
+ */
2578
+ calculateMarketSize(input) {
2579
+ return {
2580
+ tam: input.totalMarketUsd,
2581
+ sam: input.totalMarketUsd * input.serviceablePercent,
2582
+ som: input.totalMarketUsd * input.serviceablePercent * input.obtainablePercent,
2583
+ year: input.year,
2584
+ growthRate: input.growthRate,
2585
+ assumptions: input.assumptions
2586
+ };
2587
+ }
2588
+ /**
2589
+ * Calculate Unit Economics
2590
+ */
2591
+ calculateUnitEconomics(input) {
2592
+ const netChurn = input.churnRate - input.expansionRate;
2593
+ const effectiveChurn = Math.max(netChurn, 1e-3);
2594
+ const ltv = input.arpu * input.grossMargin / effectiveChurn;
2595
+ const paybackMonths = input.cac / (input.arpu * input.grossMargin);
2596
+ return {
2597
+ arpu: input.arpu,
2598
+ cac: input.cac,
2599
+ ltv: Math.round(ltv * 100) / 100,
2600
+ ltvCacRatio: Math.round(ltv / input.cac * 100) / 100,
2601
+ paybackMonths: Math.round(paybackMonths * 10) / 10,
2602
+ grossMargin: input.grossMargin,
2603
+ churnRate: input.churnRate,
2604
+ expansionRate: input.expansionRate
2605
+ };
2606
+ }
2607
+ /**
2608
+ * DCF Valuation
2609
+ */
2610
+ calculateDCF(input) {
2611
+ const fcfs = [];
2612
+ const discountedFcfs = [];
2613
+ for (let i = 0; i < input.projectedRevenues.length; i++) {
2614
+ const revenue = input.projectedRevenues[i];
2615
+ const operatingIncome = revenue * input.operatingMargin;
2616
+ const afterTax = operatingIncome * (1 - input.taxRate);
2617
+ const capex = revenue * input.capexRatio;
2618
+ const fcf = afterTax - capex;
2619
+ fcfs.push(fcf);
2620
+ const discountFactor = Math.pow(1 + input.discountRate, i + 1);
2621
+ discountedFcfs.push(fcf / discountFactor);
2622
+ }
2623
+ const presentValue = discountedFcfs.reduce((sum, v) => sum + v, 0);
2624
+ const lastFcf = fcfs[fcfs.length - 1] ?? 0;
2625
+ const terminalFcf = lastFcf * (1 + input.terminalGrowthRate);
2626
+ const terminalValue = terminalFcf / (input.discountRate - input.terminalGrowthRate);
2627
+ const discountedTerminal = terminalValue / Math.pow(1 + input.discountRate, input.projectedRevenues.length);
2628
+ const enterpriseValue = presentValue + discountedTerminal;
2629
+ const lastRevenue = input.projectedRevenues[input.projectedRevenues.length - 1] ?? 1;
2630
+ const impliedMultiple = enterpriseValue / lastRevenue;
2631
+ return {
2632
+ presentValue: Math.round(presentValue),
2633
+ terminalValue: Math.round(discountedTerminal),
2634
+ enterpriseValue: Math.round(enterpriseValue),
2635
+ freeCashFlows: fcfs.map((v) => Math.round(v)),
2636
+ discountedCashFlows: discountedFcfs.map((v) => Math.round(v)),
2637
+ impliedMultiple: Math.round(impliedMultiple * 10) / 10
2638
+ };
2639
+ }
2640
+ /**
2641
+ * Comparable Company Valuation
2642
+ */
2643
+ calculateComparable(input) {
2644
+ const revMultiples = input.comparables.map((c) => c.evRevenue);
2645
+ const ebitdaMultiples = input.comparables.map((c) => c.evEbitda);
2646
+ const userValues = input.comparables.map((c) => c.evUser);
2647
+ const medianRevMultiple = this.median(revMultiples);
2648
+ const medianEbitdaMultiple = this.median(ebitdaMultiples);
2649
+ const medianUserValue = this.median(userValues);
2650
+ const revenueVal = input.revenue * medianRevMultiple;
2651
+ const ebitdaVal = input.ebitda * medianEbitdaMultiple;
2652
+ const userVal = input.users * medianUserValue;
2653
+ const avgCompGrowth = input.comparables.reduce((s, c) => s + c.growthRate, 0) / input.comparables.length;
2654
+ const growthPremium = input.growthRate / (avgCompGrowth || 0.1);
2655
+ const growthAdjusted = revenueVal * Math.min(growthPremium, 3);
2656
+ return {
2657
+ revenueMultipleValuation: Math.round(revenueVal),
2658
+ ebitdaMultipleValuation: Math.round(ebitdaVal),
2659
+ perUserValuation: Math.round(userVal),
2660
+ averageValuation: Math.round((revenueVal + ebitdaVal + userVal) / 3),
2661
+ medianMultiple: medianRevMultiple,
2662
+ growthAdjustedValuation: Math.round(growthAdjusted)
2663
+ };
2664
+ }
2665
+ /**
2666
+ * Network Effect Valuation (Metcalfe's Law)
2667
+ */
2668
+ calculateNetworkEffect(input) {
2669
+ const currentValue = Math.pow(input.currentUsers, input.metcalfeExponent) * input.valuePerConnection * input.networkDensity;
2670
+ const projectedValues = input.projectedUsers.map(
2671
+ (users) => Math.pow(users, input.metcalfeExponent) * input.valuePerConnection * input.networkDensity
2672
+ );
2673
+ const metcalfeValue = Math.pow(input.currentUsers, 2) * input.valuePerConnection;
2674
+ const adjustedValue = metcalfeValue * input.networkDensity;
2675
+ return {
2676
+ currentNetworkValue: Math.round(currentValue),
2677
+ projectedValues: projectedValues.map((v) => Math.round(v)),
2678
+ metcalfeValue: Math.round(metcalfeValue),
2679
+ adjustedValue: Math.round(adjustedValue)
2680
+ };
2681
+ }
2682
+ /**
2683
+ * Sensitivity Analysis
2684
+ */
2685
+ runSensitivity(baseInput, variables) {
2686
+ const baseResult = this.calculateDCF(baseInput);
2687
+ const baseCase = baseResult.enterpriseValue;
2688
+ const scenarios = [];
2689
+ const tornado = [];
2690
+ for (const v of variables) {
2691
+ const lowInput = { ...baseInput, [v.field]: v.low };
2692
+ const lowResult = this.calculateDCF(lowInput);
2693
+ const highInput = { ...baseInput, [v.field]: v.high };
2694
+ const highResult = this.calculateDCF(highInput);
2695
+ scenarios.push({
2696
+ name: `${v.name} Low`,
2697
+ value: lowResult.enterpriseValue,
2698
+ delta: (lowResult.enterpriseValue - baseCase) / baseCase * 100,
2699
+ variables: { [v.name]: v.low }
2700
+ });
2701
+ scenarios.push({
2702
+ name: `${v.name} High`,
2703
+ value: highResult.enterpriseValue,
2704
+ delta: (highResult.enterpriseValue - baseCase) / baseCase * 100,
2705
+ variables: { [v.name]: v.high }
2706
+ });
2707
+ tornado.push({
2708
+ variable: v.name,
2709
+ lowValue: lowResult.enterpriseValue,
2710
+ highValue: highResult.enterpriseValue,
2711
+ range: Math.abs(highResult.enterpriseValue - lowResult.enterpriseValue)
2712
+ });
2713
+ }
2714
+ tornado.sort((a, b) => b.range - a.range);
2715
+ return { baseCase, scenarios, tornado };
2716
+ }
2717
+ // ─── Helpers ─────────────────────────────────────────────────────
2718
+ median(values) {
2719
+ if (values.length === 0) return 0;
2720
+ const sorted = [...values].sort((a, b) => a - b);
2721
+ const mid = Math.floor(sorted.length / 2);
2722
+ return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
2723
+ }
2724
+ };
2725
+
2726
+ // src/governanceEnhancer.ts
2727
+ var DEFAULT_GE_CONFIG = {
2728
+ circuitBreakerThreshold: 5,
2729
+ circuitBreakerTimeoutMs: 3e4,
2730
+ halfOpenSuccessThreshold: 3,
2731
+ degradationChain: [
2732
+ {
2733
+ id: "full",
2734
+ name: "Full Capability",
2735
+ order: 4,
2736
+ capabilities: ["all"],
2737
+ restrictions: []
2738
+ },
2739
+ {
2740
+ id: "reduced",
2741
+ name: "Reduced Capability",
2742
+ order: 3,
2743
+ capabilities: ["read", "compute", "cache"],
2744
+ restrictions: ["write", "external_api"]
2745
+ },
2746
+ {
2747
+ id: "minimal",
2748
+ name: "Minimal Capability",
2749
+ order: 2,
2750
+ capabilities: ["read", "cache"],
2751
+ restrictions: ["write", "compute", "external_api"]
2752
+ },
2753
+ {
2754
+ id: "readonly",
2755
+ name: "Read-Only Mode",
2756
+ order: 1,
2757
+ capabilities: ["read"],
2758
+ restrictions: ["write", "compute", "external_api", "cache"]
2759
+ }
2760
+ ],
2761
+ maxPolicyVersions: 10
2762
+ };
2763
+ function simpleHash2(input) {
2764
+ let hash = 0;
2765
+ for (let i = 0; i < input.length; i++) {
2766
+ hash = (hash << 5) - hash + input.charCodeAt(i);
2767
+ hash = hash & hash;
2768
+ }
2769
+ return Math.abs(hash).toString(16).padStart(8, "0");
2770
+ }
2771
+ var GovernanceEnhancer = class {
2772
+ currentPolicy = null;
2773
+ policyHistory = [];
2774
+ circuitBreakers = /* @__PURE__ */ new Map();
2775
+ currentDegradationLevel = "full";
2776
+ config;
2777
+ constructor(config) {
2778
+ this.config = { ...DEFAULT_GE_CONFIG, ...config };
2779
+ }
2780
+ // ─── Policy Hot-Reload ───────────────────────────────────────────
2781
+ /**
2782
+ * Load a new policy version (hot-reload)
2783
+ */
2784
+ async loadPolicy(version, rules) {
2785
+ const hash = simpleHash2(JSON.stringify(rules));
2786
+ const oldVersion = this.currentPolicy?.version;
2787
+ const newPolicy = {
2788
+ version,
2789
+ rules: rules.sort((a, b) => b.priority - a.priority),
2790
+ activatedAt: Date.now(),
2791
+ hash
2792
+ };
2793
+ if (this.currentPolicy) {
2794
+ this.policyHistory.push(this.currentPolicy);
2795
+ if (this.policyHistory.length > this.config.maxPolicyVersions) {
2796
+ this.policyHistory = this.policyHistory.slice(-this.config.maxPolicyVersions);
2797
+ }
2798
+ }
2799
+ this.currentPolicy = newPolicy;
2800
+ if (this.config.onPolicyChange && oldVersion) {
2801
+ try {
2802
+ await this.config.onPolicyChange(oldVersion, version);
2803
+ } catch {
2804
+ }
2805
+ }
2806
+ if (this.config.onAudit) {
2807
+ try {
2808
+ await this.config.onAudit({
2809
+ type: "policy_loaded",
2810
+ data: { version, ruleCount: rules.length, hash, previousVersion: oldVersion }
2811
+ });
2812
+ } catch {
2813
+ }
2814
+ }
2815
+ return { success: true, previousVersion: oldVersion, newVersion: version };
2816
+ }
2817
+ /**
2818
+ * Rollback to a previous policy version
2819
+ */
2820
+ async rollbackPolicy(version) {
2821
+ const target = this.policyHistory.find((p) => p.version === version);
2822
+ if (!target) return false;
2823
+ if (this.currentPolicy) {
2824
+ this.policyHistory.push(this.currentPolicy);
2825
+ }
2826
+ this.currentPolicy = { ...target, activatedAt: Date.now() };
2827
+ return true;
2828
+ }
2829
+ /**
2830
+ * Evaluate a governance decision
2831
+ */
2832
+ async evaluate(context) {
2833
+ if (!this.currentPolicy) {
2834
+ return {
2835
+ allowed: false,
2836
+ action: "deny",
2837
+ reason: "No policy loaded",
2838
+ policyVersion: "none"
2839
+ };
2840
+ }
2841
+ const cbState = this.getCircuitBreakerState(context.resource);
2842
+ if (cbState === "OPEN") {
2843
+ return {
2844
+ allowed: false,
2845
+ action: "deny",
2846
+ circuitState: "OPEN",
2847
+ reason: `Circuit breaker OPEN for ${context.resource}`,
2848
+ policyVersion: this.currentPolicy.version
2849
+ };
2850
+ }
2851
+ for (const rule of this.currentPolicy.rules) {
2852
+ if (!rule.enabled) continue;
2853
+ const matches = this.evaluateCondition(rule.condition, context);
2854
+ if (!matches) continue;
2855
+ const decision = {
2856
+ allowed: rule.action === "allow",
2857
+ action: rule.action,
2858
+ ruleId: rule.id,
2859
+ ruleName: rule.name,
2860
+ circuitState: cbState,
2861
+ policyVersion: this.currentPolicy.version,
2862
+ reason: `Rule ${rule.name} matched: ${rule.action}`
2863
+ };
2864
+ if (rule.action === "degrade" && rule.degradeTo) {
2865
+ decision.degradationLevel = rule.degradeTo;
2866
+ decision.allowed = true;
2867
+ this.currentDegradationLevel = rule.degradeTo;
2868
+ }
2869
+ if (this.config.onAudit) {
2870
+ try {
2871
+ await this.config.onAudit({
2872
+ type: "governance_decision",
2873
+ data: {
2874
+ action: context.action,
2875
+ resource: context.resource,
2876
+ decision: rule.action,
2877
+ ruleId: rule.id,
2878
+ policyVersion: this.currentPolicy.version
2879
+ }
2880
+ });
2881
+ } catch {
2882
+ }
2883
+ }
2884
+ return decision;
2885
+ }
2886
+ return {
2887
+ allowed: true,
2888
+ action: "allow",
2889
+ reason: "No matching rule, default allow",
2890
+ policyVersion: this.currentPolicy.version,
2891
+ circuitState: cbState
2892
+ };
2893
+ }
2894
+ // ─── Circuit Breaker ─────────────────────────────────────────────
2895
+ /**
2896
+ * Record a success for circuit breaker
2897
+ */
2898
+ recordSuccess(resource) {
2899
+ const cb = this.getOrCreateCircuitBreaker(resource);
2900
+ cb.successCount++;
2901
+ cb.lastSuccessAt = Date.now();
2902
+ if (cb.state === "HALF_OPEN") {
2903
+ if (cb.successCount >= this.config.halfOpenSuccessThreshold) {
2904
+ cb.state = "CLOSED";
2905
+ cb.failureCount = 0;
2906
+ cb.halfOpenAttempts = 0;
2907
+ }
2908
+ }
2909
+ }
2910
+ /**
2911
+ * Record a failure for circuit breaker
2912
+ */
2913
+ recordFailure(resource) {
2914
+ const cb = this.getOrCreateCircuitBreaker(resource);
2915
+ cb.failureCount++;
2916
+ cb.lastFailureAt = Date.now();
2917
+ if (cb.state === "CLOSED" && cb.failureCount >= this.config.circuitBreakerThreshold) {
2918
+ cb.state = "OPEN";
2919
+ cb.openedAt = Date.now();
2920
+ } else if (cb.state === "HALF_OPEN") {
2921
+ cb.state = "OPEN";
2922
+ cb.openedAt = Date.now();
2923
+ cb.halfOpenAttempts++;
2924
+ }
2925
+ }
2926
+ /**
2927
+ * Get circuit breaker state for a resource
2928
+ */
2929
+ getCircuitBreakerState(resource) {
2930
+ const cb = this.circuitBreakers.get(resource);
2931
+ if (!cb) return "CLOSED";
2932
+ if (cb.state === "OPEN") {
2933
+ const elapsed = Date.now() - cb.openedAt;
2934
+ if (elapsed >= this.config.circuitBreakerTimeoutMs) {
2935
+ cb.state = "HALF_OPEN";
2936
+ cb.successCount = 0;
2937
+ }
2938
+ }
2939
+ return cb.state;
2940
+ }
2941
+ // ─── Degradation Chain ───────────────────────────────────────────
2942
+ /**
2943
+ * Get current degradation level
2944
+ */
2945
+ getCurrentDegradationLevel() {
2946
+ return this.config.degradationChain.find((d) => d.id === this.currentDegradationLevel);
2947
+ }
2948
+ /**
2949
+ * Degrade to next level
2950
+ */
2951
+ degradeOneLevel() {
2952
+ const current = this.config.degradationChain.find((d) => d.id === this.currentDegradationLevel);
2953
+ if (!current) return null;
2954
+ const nextLevel = this.config.degradationChain.filter((d) => d.order < current.order).sort((a, b) => b.order - a.order)[0];
2955
+ if (nextLevel) {
2956
+ this.currentDegradationLevel = nextLevel.id;
2957
+ return nextLevel;
2958
+ }
2959
+ return null;
2960
+ }
2961
+ /**
2962
+ * Restore to full capability
2963
+ */
2964
+ restoreFullCapability() {
2965
+ this.currentDegradationLevel = "full";
2966
+ }
2967
+ /**
2968
+ * Check if a capability is available at current degradation level
2969
+ */
2970
+ isCapabilityAvailable(capability) {
2971
+ const level = this.getCurrentDegradationLevel();
2972
+ if (!level) return false;
2973
+ return level.capabilities.includes("all") || level.capabilities.includes(capability);
2974
+ }
2975
+ // ─── Status ──────────────────────────────────────────────────────
2976
+ /**
2977
+ * Get full governance status
2978
+ */
2979
+ getStatus() {
2980
+ return {
2981
+ policyVersion: this.currentPolicy?.version ?? null,
2982
+ ruleCount: this.currentPolicy?.rules.length ?? 0,
2983
+ degradationLevel: this.currentDegradationLevel,
2984
+ circuitBreakers: Array.from(this.circuitBreakers.values()),
2985
+ policyHistoryCount: this.policyHistory.length
2986
+ };
2987
+ }
2988
+ // ─── Internal ────────────────────────────────────────────────────
2989
+ evaluateCondition(condition, context) {
2990
+ if (condition === "*") return true;
2991
+ if (condition.startsWith("action:")) {
2992
+ return context.action === condition.substring(7);
2993
+ }
2994
+ if (condition.startsWith("resource:")) {
2995
+ return context.resource.includes(condition.substring(9));
2996
+ }
2997
+ if (condition.startsWith("agent:")) {
2998
+ return context.agentId === condition.substring(6);
2999
+ }
3000
+ return false;
3001
+ }
3002
+ getOrCreateCircuitBreaker(resource) {
3003
+ let cb = this.circuitBreakers.get(resource);
3004
+ if (!cb) {
3005
+ cb = {
3006
+ name: resource,
3007
+ state: "CLOSED",
3008
+ failureCount: 0,
3009
+ successCount: 0,
3010
+ lastFailureAt: 0,
3011
+ lastSuccessAt: 0,
3012
+ openedAt: 0,
3013
+ halfOpenAttempts: 0
3014
+ };
3015
+ this.circuitBreakers.set(resource, cb);
3016
+ }
3017
+ return cb;
3018
+ }
3019
+ };
3020
+
3021
+ // src/contextAccelerator.ts
3022
+ var DEFAULT_CA_CONFIG = {
3023
+ maxCacheEntries: 500,
3024
+ defaultTtlMs: 3e5,
3025
+ // 5 minutes
3026
+ tokenBudget: 8e3,
3027
+ compressionTarget: 0.5,
3028
+ priorityWeights: {
3029
+ critical: 100,
3030
+ high: 75,
3031
+ medium: 50,
3032
+ low: 25
3033
+ }
3034
+ };
3035
+ function estimateTokens(text) {
3036
+ return Math.ceil(text.length / 3.5);
3037
+ }
3038
+ function defaultCompressor(content, targetTokens) {
3039
+ const currentTokens = estimateTokens(content);
3040
+ if (currentTokens <= targetTokens) return content;
3041
+ const ratio = targetTokens / currentTokens;
3042
+ const targetLength = Math.floor(content.length * ratio);
3043
+ if (targetLength < 50) return content.substring(0, 50) + "...";
3044
+ return content.substring(0, targetLength) + "...[compressed]";
3045
+ }
3046
+ var ContextAccelerator = class {
3047
+ cache = /* @__PURE__ */ new Map();
3048
+ prefetchRules = /* @__PURE__ */ new Map();
3049
+ config;
3050
+ stats = {
3051
+ totalHits: 0,
3052
+ totalMisses: 0,
3053
+ totalEvictions: 0,
3054
+ totalCompressions: 0,
3055
+ totalAssemblies: 0
3056
+ };
3057
+ constructor(config) {
3058
+ this.config = { ...DEFAULT_CA_CONFIG, ...config };
3059
+ }
3060
+ /**
3061
+ * Put a fragment into cache
3062
+ */
3063
+ put(fragment) {
3064
+ this.evictExpired();
3065
+ if (this.cache.size >= this.config.maxCacheEntries) {
3066
+ this.evictLRU();
3067
+ }
3068
+ this.cache.set(fragment.id, {
3069
+ fragment,
3070
+ accessCount: 0,
3071
+ lastAccessedAt: Date.now(),
3072
+ createdAt: Date.now(),
3073
+ expiresAt: Date.now() + (fragment.ttlMs || this.config.defaultTtlMs)
3074
+ });
3075
+ }
3076
+ /**
3077
+ * Get a fragment from cache
3078
+ */
3079
+ get(id) {
3080
+ const entry = this.cache.get(id);
3081
+ if (!entry) {
3082
+ this.stats.totalMisses++;
3083
+ return null;
3084
+ }
3085
+ if (Date.now() > entry.expiresAt) {
3086
+ this.cache.delete(id);
3087
+ this.stats.totalMisses++;
3088
+ return null;
3089
+ }
3090
+ entry.accessCount++;
3091
+ entry.lastAccessedAt = Date.now();
3092
+ this.stats.totalHits++;
3093
+ return entry.fragment;
3094
+ }
3095
+ /**
3096
+ * Assemble context from fragments within token budget
3097
+ */
3098
+ async assemble(fragmentIds, additionalFragments, budgetOverride) {
3099
+ const startTime = Date.now();
3100
+ const budget = budgetOverride ?? this.config.tokenBudget;
3101
+ let cacheHits = 0;
3102
+ let cacheMisses = 0;
3103
+ const allFragments = [];
3104
+ for (const id of fragmentIds) {
3105
+ const fragment = this.get(id);
3106
+ if (fragment) {
3107
+ allFragments.push(fragment);
3108
+ cacheHits++;
3109
+ } else {
3110
+ cacheMisses++;
3111
+ }
3112
+ }
3113
+ if (additionalFragments) {
3114
+ allFragments.push(...additionalFragments);
3115
+ }
3116
+ const weights = this.config.priorityWeights;
3117
+ allFragments.sort((a, b) => {
3118
+ const wDiff = (weights[b.priority] ?? 0) - (weights[a.priority] ?? 0);
3119
+ if (wDiff !== 0) return wDiff;
3120
+ return b.timestamp - a.timestamp;
3121
+ });
3122
+ const selected = [];
3123
+ let totalTokens = 0;
3124
+ let droppedCount = 0;
3125
+ let compressedCount = 0;
3126
+ for (const fragment of allFragments) {
3127
+ if (totalTokens >= budget) {
3128
+ droppedCount++;
3129
+ continue;
3130
+ }
3131
+ const remaining = budget - totalTokens;
3132
+ if (fragment.tokenCount <= remaining) {
3133
+ selected.push(fragment);
3134
+ totalTokens += fragment.tokenCount;
3135
+ } else if (fragment.priority === "critical" || fragment.priority === "high") {
3136
+ const compressor = this.config.compressor ?? defaultCompressor;
3137
+ const compressed = compressor(fragment.content, remaining);
3138
+ const compressedTokens = estimateTokens(compressed);
3139
+ selected.push({
3140
+ ...fragment,
3141
+ content: compressed,
3142
+ tokenCount: compressedTokens,
3143
+ compressed: true
3144
+ });
3145
+ totalTokens += compressedTokens;
3146
+ compressedCount++;
3147
+ this.stats.totalCompressions++;
3148
+ } else {
3149
+ droppedCount++;
3150
+ }
3151
+ }
3152
+ this.stats.totalAssemblies++;
3153
+ const result = {
3154
+ fragments: selected,
3155
+ totalTokens,
3156
+ budgetUsed: budget > 0 ? totalTokens / budget : 0,
3157
+ droppedCount,
3158
+ compressedCount,
3159
+ cacheHits,
3160
+ cacheMisses,
3161
+ assemblyTimeMs: Date.now() - startTime
3162
+ };
3163
+ if (this.config.onAudit) {
3164
+ try {
3165
+ await this.config.onAudit({
3166
+ type: "context_assembled",
3167
+ data: {
3168
+ totalTokens,
3169
+ budgetUsed: result.budgetUsed,
3170
+ fragmentCount: selected.length,
3171
+ droppedCount,
3172
+ compressedCount,
3173
+ cacheHits,
3174
+ cacheMisses,
3175
+ assemblyTimeMs: result.assemblyTimeMs
3176
+ }
3177
+ });
3178
+ } catch {
3179
+ }
3180
+ }
3181
+ return result;
3182
+ }
3183
+ /**
3184
+ * Register a prefetch rule
3185
+ */
3186
+ addPrefetchRule(rule) {
3187
+ this.prefetchRules.set(rule.id, rule);
3188
+ }
3189
+ /**
3190
+ * Execute prefetch based on task type
3191
+ */
3192
+ async prefetch(taskType, fragmentLoader) {
3193
+ const matchingRules = Array.from(this.prefetchRules.values()).filter(
3194
+ (r) => r.enabled && taskType.includes(r.trigger)
3195
+ );
3196
+ if (matchingRules.length === 0) return 0;
3197
+ const idsToFetch = /* @__PURE__ */ new Set();
3198
+ for (const rule of matchingRules) {
3199
+ for (const id of rule.fragmentIds) {
3200
+ if (!this.cache.has(id)) {
3201
+ idsToFetch.add(id);
3202
+ }
3203
+ }
3204
+ }
3205
+ if (idsToFetch.size === 0) return 0;
3206
+ const fragments = await fragmentLoader(Array.from(idsToFetch));
3207
+ for (const f of fragments) {
3208
+ this.put(f);
3209
+ }
3210
+ return fragments.length;
3211
+ }
3212
+ /**
3213
+ * Invalidate cache entries
3214
+ */
3215
+ invalidate(ids) {
3216
+ let count = 0;
3217
+ for (const id of ids) {
3218
+ if (this.cache.delete(id)) count++;
3219
+ }
3220
+ return count;
3221
+ }
3222
+ /**
3223
+ * Get cache stats
3224
+ */
3225
+ getStats() {
3226
+ const total = this.stats.totalHits + this.stats.totalMisses;
3227
+ return {
3228
+ cacheSize: this.cache.size,
3229
+ maxSize: this.config.maxCacheEntries,
3230
+ hitRate: total > 0 ? this.stats.totalHits / total : 0,
3231
+ ...this.stats,
3232
+ prefetchRuleCount: this.prefetchRules.size
3233
+ };
3234
+ }
3235
+ /**
3236
+ * Clear all cache
3237
+ */
3238
+ clear() {
3239
+ this.cache.clear();
3240
+ }
3241
+ // ─── Internal ────────────────────────────────────────────────────
3242
+ evictExpired() {
3243
+ const now = Date.now();
3244
+ for (const [id, entry] of this.cache) {
3245
+ if (now > entry.expiresAt) {
3246
+ this.cache.delete(id);
3247
+ this.stats.totalEvictions++;
3248
+ }
3249
+ }
3250
+ }
3251
+ evictLRU() {
3252
+ let oldestId = null;
3253
+ let oldestAccess = Infinity;
3254
+ for (const [id, entry] of this.cache) {
3255
+ if (entry.lastAccessedAt < oldestAccess) {
3256
+ oldestAccess = entry.lastAccessedAt;
3257
+ oldestId = id;
3258
+ }
3259
+ }
3260
+ if (oldestId) {
3261
+ this.cache.delete(oldestId);
3262
+ this.stats.totalEvictions++;
3263
+ }
3264
+ }
3265
+ };
3266
+
2057
3267
  // src/index.ts
2058
3268
  var DEFAULT_RULES = [
2059
3269
  // --- HTTP Proxy: Dangerous outbound calls ---
@@ -2545,16 +3755,26 @@ var index_default = PolicyEngine;
2545
3755
  0 && (module.exports = {
2546
3756
  AdaptiveThresholdManager,
2547
3757
  AutoHardenEngine,
3758
+ ContextAccelerator,
2548
3759
  CostGateEnhancedEngine,
3760
+ DEFAULT_CA_CONFIG,
3761
+ DEFAULT_GE_CONFIG,
3762
+ DEFAULT_HARD_RULES,
2549
3763
  DEFAULT_RULES,
3764
+ DEFAULT_SCORING_WEIGHTS,
3765
+ DEFAULT_TSA_CONFIG,
2550
3766
  EvolutionChannelEngine,
2551
3767
  FeatureSwitchesManager,
3768
+ GovernanceEnhancer,
2552
3769
  MultiLevelBudgetEngine,
2553
3770
  PolicyEngine,
2554
3771
  PricingRulesEngine,
2555
3772
  RecalculationEngine,
2556
3773
  SOVR_FEATURE_SWITCHES,
2557
3774
  SemanticDriftDetectorEngine,
3775
+ TimeSeriesAggregator,
3776
+ TwoPhaseRouter,
3777
+ ValuationModel,
2558
3778
  compileFromJSON,
2559
3779
  compileRuleSet,
2560
3780
  createAutoHardenEngine,