@sovr/engine 3.4.0 → 3.6.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,30 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AdaptiveThresholdManager: () => AdaptiveThresholdManager,
24
24
  AutoHardenEngine: () => AutoHardenEngine,
25
+ ContextAccelerator: () => ContextAccelerator,
26
+ ContributionSettlementEngine: () => ContributionSettlementEngine,
25
27
  CostGateEnhancedEngine: () => CostGateEnhancedEngine,
28
+ DEFAULT_CA_CONFIG: () => DEFAULT_CA_CONFIG,
29
+ DEFAULT_GE_CONFIG: () => DEFAULT_GE_CONFIG,
30
+ DEFAULT_HARD_RULES: () => DEFAULT_HARD_RULES,
26
31
  DEFAULT_RULES: () => DEFAULT_RULES,
32
+ DEFAULT_SCORING_WEIGHTS: () => DEFAULT_SCORING_WEIGHTS,
33
+ DEFAULT_TSA_CONFIG: () => DEFAULT_TSA_CONFIG,
27
34
  EvolutionChannelEngine: () => EvolutionChannelEngine,
28
35
  FeatureSwitchesManager: () => FeatureSwitchesManager,
36
+ GovernanceEnhancer: () => GovernanceEnhancer,
29
37
  MultiLevelBudgetEngine: () => MultiLevelBudgetEngine,
38
+ OverrideDriftAnalyzer: () => OverrideDriftAnalyzer,
30
39
  PolicyEngine: () => PolicyEngine,
31
40
  PricingRulesEngine: () => PricingRulesEngine,
32
41
  RecalculationEngine: () => RecalculationEngine,
33
42
  SOVR_FEATURE_SWITCHES: () => SOVR_FEATURE_SWITCHES,
43
+ SelfConstraintEngine: () => SelfConstraintEngine,
34
44
  SemanticDriftDetectorEngine: () => SemanticDriftDetectorEngine,
45
+ TimeSeriesAggregator: () => TimeSeriesAggregator,
46
+ TrendAlertEngine: () => TrendAlertEngine,
47
+ TwoPhaseRouter: () => TwoPhaseRouter,
48
+ ValuationModel: () => ValuationModel,
35
49
  compileFromJSON: () => compileFromJSON,
36
50
  compileRuleSet: () => compileRuleSet,
37
51
  createAutoHardenEngine: () => createAutoHardenEngine,
@@ -2054,6 +2068,2264 @@ function createEvolutionChannel(config) {
2054
2068
  return new EvolutionChannelEngine(config);
2055
2069
  }
2056
2070
 
2071
+ // src/twoPhaseRouter.ts
2072
+ var DEFAULT_HARD_RULES = [
2073
+ {
2074
+ id: "HR-001",
2075
+ name: "high_risk_requires_powerful",
2076
+ condition: (req, candidate) => (req.riskLevel === "critical" || req.riskLevel === "high") && candidate.tier === "cheap",
2077
+ reasonCode: "RISK_TIER_MISMATCH",
2078
+ reasonTemplate: "High/critical risk tasks cannot use cheap tier models",
2079
+ enabled: true
2080
+ },
2081
+ {
2082
+ id: "HR-002",
2083
+ name: "critical_requires_powerful_only",
2084
+ condition: (req, candidate) => req.riskLevel === "critical" && candidate.tier !== "powerful",
2085
+ reasonCode: "RISK_TIER_MISMATCH",
2086
+ reasonTemplate: "Critical risk tasks require powerful tier models only",
2087
+ enabled: true
2088
+ },
2089
+ {
2090
+ id: "HR-003",
2091
+ name: "budget_hard_cap",
2092
+ condition: (req, candidate) => {
2093
+ if (!req.maxCostUsd) return false;
2094
+ const estimatedCost = req.estimatedTokens / 1e3 * candidate.costPer1kTokens;
2095
+ return estimatedCost > req.maxCostUsd;
2096
+ },
2097
+ reasonCode: "COST_EXCEEDS_BUDGET",
2098
+ reasonTemplate: "Estimated cost exceeds hard budget cap",
2099
+ enabled: true
2100
+ }
2101
+ ];
2102
+ var DEFAULT_SCORING_WEIGHTS = {
2103
+ cost: 0.25,
2104
+ latency: 0.2,
2105
+ capability: 0.25,
2106
+ weight: 0.15,
2107
+ tierMatch: 0.15
2108
+ };
2109
+ var TwoPhaseRouter = class {
2110
+ config;
2111
+ constructor(config) {
2112
+ this.config = {
2113
+ ...config,
2114
+ hardRules: config.hardRules.length > 0 ? config.hardRules : DEFAULT_HARD_RULES,
2115
+ scoringWeights: config.scoringWeights ?? DEFAULT_SCORING_WEIGHTS
2116
+ };
2117
+ }
2118
+ /**
2119
+ * Phase 1: Eligibility — 硬性规则过滤
2120
+ */
2121
+ evaluateEligibility(request) {
2122
+ return this.config.models.map((candidate) => {
2123
+ if (!candidate.enabled) {
2124
+ return {
2125
+ candidateId: candidate.id,
2126
+ eligible: false,
2127
+ reasonCode: "DISABLED",
2128
+ reasonDetail: `Model ${candidate.name} is disabled`
2129
+ };
2130
+ }
2131
+ const missingCaps = request.requiredCapabilities.filter(
2132
+ (cap) => !candidate.capabilities.includes(cap)
2133
+ );
2134
+ if (missingCaps.length > 0) {
2135
+ return {
2136
+ candidateId: candidate.id,
2137
+ eligible: false,
2138
+ reasonCode: "CAPABILITY_MISSING",
2139
+ reasonDetail: `Missing capabilities: ${missingCaps.join(", ")}`
2140
+ };
2141
+ }
2142
+ if (request.estimatedTokens > candidate.maxContextTokens) {
2143
+ return {
2144
+ candidateId: candidate.id,
2145
+ eligible: false,
2146
+ reasonCode: "CONTEXT_TOO_LARGE",
2147
+ reasonDetail: `Estimated ${request.estimatedTokens} tokens exceeds max ${candidate.maxContextTokens}`
2148
+ };
2149
+ }
2150
+ if (request.maxLatencyMs && candidate.avgLatencyMs > request.maxLatencyMs) {
2151
+ return {
2152
+ candidateId: candidate.id,
2153
+ eligible: false,
2154
+ reasonCode: "LATENCY_EXCEEDS_LIMIT",
2155
+ reasonDetail: `Avg latency ${candidate.avgLatencyMs}ms exceeds limit ${request.maxLatencyMs}ms`
2156
+ };
2157
+ }
2158
+ for (const rule of this.config.hardRules) {
2159
+ if (!rule.enabled) continue;
2160
+ if (rule.condition(request, candidate)) {
2161
+ return {
2162
+ candidateId: candidate.id,
2163
+ eligible: false,
2164
+ reasonCode: rule.reasonCode,
2165
+ reasonDetail: rule.reasonTemplate
2166
+ };
2167
+ }
2168
+ }
2169
+ return {
2170
+ candidateId: candidate.id,
2171
+ eligible: true,
2172
+ reasonCode: "ELIGIBLE",
2173
+ reasonDetail: "Passed all eligibility checks"
2174
+ };
2175
+ });
2176
+ }
2177
+ /**
2178
+ * Phase 2: Scoring — 软性指标加权评分
2179
+ */
2180
+ evaluateScoring(request, eligibleIds) {
2181
+ const eligible = this.config.models.filter((m) => eligibleIds.has(m.id));
2182
+ if (eligible.length === 0) return [];
2183
+ const w = this.config.scoringWeights;
2184
+ const maxCost = Math.max(...eligible.map((m) => m.costPer1kTokens), 1e-3);
2185
+ const maxLatency = Math.max(...eligible.map((m) => m.avgLatencyMs), 1);
2186
+ return eligible.map((candidate) => {
2187
+ const costScore = 100 * (1 - candidate.costPer1kTokens / maxCost);
2188
+ const latencyScore = 100 * (1 - candidate.avgLatencyMs / maxLatency);
2189
+ const matchedCaps = request.requiredCapabilities.filter(
2190
+ (cap) => candidate.capabilities.includes(cap)
2191
+ ).length;
2192
+ const capabilityScore = request.requiredCapabilities.length > 0 ? 100 * (matchedCaps / request.requiredCapabilities.length) : 50;
2193
+ const weightScore = candidate.weight;
2194
+ let tierMatchScore = 50;
2195
+ if (request.preferredTier) {
2196
+ if (candidate.tier === request.preferredTier) tierMatchScore = 100;
2197
+ else {
2198
+ const tierOrder = ["cheap", "balanced", "powerful"];
2199
+ const diff = Math.abs(
2200
+ tierOrder.indexOf(candidate.tier) - tierOrder.indexOf(request.preferredTier)
2201
+ );
2202
+ tierMatchScore = Math.max(0, 100 - diff * 40);
2203
+ }
2204
+ }
2205
+ const score = costScore * w.cost + latencyScore * w.latency + capabilityScore * w.capability + weightScore * w.weight + tierMatchScore * w.tierMatch;
2206
+ return {
2207
+ candidateId: candidate.id,
2208
+ score: Math.round(score * 100) / 100,
2209
+ breakdown: {
2210
+ costScore: Math.round(costScore * 100) / 100,
2211
+ latencyScore: Math.round(latencyScore * 100) / 100,
2212
+ capabilityScore: Math.round(capabilityScore * 100) / 100,
2213
+ weightScore: Math.round(weightScore * 100) / 100,
2214
+ tierMatchScore: Math.round(tierMatchScore * 100) / 100
2215
+ }
2216
+ };
2217
+ });
2218
+ }
2219
+ /**
2220
+ * Main routing decision
2221
+ */
2222
+ async route(request) {
2223
+ const startTime = Date.now();
2224
+ const phase1Results = this.evaluateEligibility(request);
2225
+ const eligibleIds = new Set(
2226
+ phase1Results.filter((r) => r.eligible).map((r) => r.candidateId)
2227
+ );
2228
+ const phase2Results = this.evaluateScoring(request, eligibleIds);
2229
+ phase2Results.sort((a, b) => b.score - a.score);
2230
+ let selectedModelId;
2231
+ let fallbackUsed = false;
2232
+ const reasonChain = [];
2233
+ if (phase2Results.length > 0) {
2234
+ selectedModelId = phase2Results[0].candidateId;
2235
+ reasonChain.push(
2236
+ `Phase 1: ${eligibleIds.size}/${this.config.models.length} candidates eligible`
2237
+ );
2238
+ reasonChain.push(
2239
+ `Phase 2: Top scorer = ${selectedModelId} (score: ${phase2Results[0].score})`
2240
+ );
2241
+ const rejected = phase1Results.filter((r) => !r.eligible);
2242
+ if (rejected.length > 0) {
2243
+ reasonChain.push(
2244
+ `Rejected: ${rejected.map((r) => `${r.candidateId}(${r.reasonCode})`).join(", ")}`
2245
+ );
2246
+ }
2247
+ } else if (this.config.fallbackModelId) {
2248
+ selectedModelId = this.config.fallbackModelId;
2249
+ fallbackUsed = true;
2250
+ reasonChain.push("Phase 1: No eligible candidates");
2251
+ reasonChain.push(`Fallback: Using ${selectedModelId}`);
2252
+ } else {
2253
+ const leastBad = this.config.models.find((m) => m.enabled);
2254
+ selectedModelId = leastBad?.id ?? this.config.models[0]?.id ?? "unknown";
2255
+ fallbackUsed = true;
2256
+ reasonChain.push("Phase 1: No eligible candidates, no fallback configured");
2257
+ reasonChain.push(`Emergency: Using ${selectedModelId}`);
2258
+ }
2259
+ const selectedModel = this.config.models.find((m) => m.id === selectedModelId);
2260
+ const decisionTimeMs = Date.now() - startTime;
2261
+ const decision = {
2262
+ selectedModelId,
2263
+ selectedModelName: selectedModel?.name ?? "unknown",
2264
+ tier: selectedModel?.tier ?? this.config.defaultTier,
2265
+ phase1Results,
2266
+ phase2Results,
2267
+ reasonChain,
2268
+ totalCandidates: this.config.models.length,
2269
+ eligibleCandidates: eligibleIds.size,
2270
+ decisionTimeMs,
2271
+ fallbackUsed
2272
+ };
2273
+ if (this.config.onDecision) {
2274
+ try {
2275
+ await this.config.onDecision(decision);
2276
+ } catch {
2277
+ }
2278
+ }
2279
+ if (this.config.onAudit) {
2280
+ try {
2281
+ await this.config.onAudit({
2282
+ type: "routing_decision",
2283
+ data: {
2284
+ selectedModelId,
2285
+ tier: decision.tier,
2286
+ eligibleCount: eligibleIds.size,
2287
+ totalCount: this.config.models.length,
2288
+ fallbackUsed,
2289
+ decisionTimeMs,
2290
+ taskType: request.taskType,
2291
+ riskLevel: request.riskLevel
2292
+ }
2293
+ });
2294
+ } catch {
2295
+ }
2296
+ }
2297
+ return decision;
2298
+ }
2299
+ /**
2300
+ * Get models by tier
2301
+ */
2302
+ getModelsByTier(tier) {
2303
+ return this.config.models.filter((m) => m.tier === tier && m.enabled);
2304
+ }
2305
+ /**
2306
+ * Update model status
2307
+ */
2308
+ updateModel(modelId, updates) {
2309
+ const idx = this.config.models.findIndex((m) => m.id === modelId);
2310
+ if (idx === -1) return false;
2311
+ this.config.models[idx] = { ...this.config.models[idx], ...updates };
2312
+ return true;
2313
+ }
2314
+ /**
2315
+ * Add a new hard rule
2316
+ */
2317
+ addHardRule(rule) {
2318
+ this.config.hardRules.push(rule);
2319
+ }
2320
+ /**
2321
+ * Get routing explanation for a specific request (dry run)
2322
+ */
2323
+ async explain(request) {
2324
+ const decision = await this.route(request);
2325
+ const lines = [
2326
+ `=== SOVR Routing Explanation ===`,
2327
+ `Task: ${request.taskType} | Risk: ${request.riskLevel}`,
2328
+ `Required Capabilities: ${request.requiredCapabilities.join(", ") || "none"}`,
2329
+ `Estimated Tokens: ${request.estimatedTokens}`,
2330
+ ``,
2331
+ `--- Phase 1: Eligibility ---`
2332
+ ];
2333
+ for (const r of decision.phase1Results) {
2334
+ const model = this.config.models.find((m) => m.id === r.candidateId);
2335
+ lines.push(
2336
+ ` ${r.eligible ? "\u2705" : "\u274C"} ${model?.name ?? r.candidateId} [${r.reasonCode}] ${r.reasonDetail}`
2337
+ );
2338
+ }
2339
+ lines.push("", `--- Phase 2: Scoring ---`);
2340
+ for (const r of decision.phase2Results) {
2341
+ const model = this.config.models.find((m) => m.id === r.candidateId);
2342
+ lines.push(
2343
+ ` ${model?.name ?? r.candidateId}: ${r.score} (cost=${r.breakdown.costScore} lat=${r.breakdown.latencyScore} cap=${r.breakdown.capabilityScore})`
2344
+ );
2345
+ }
2346
+ lines.push(
2347
+ "",
2348
+ `--- Decision ---`,
2349
+ `Selected: ${decision.selectedModelName} (${decision.tier})`,
2350
+ `Fallback: ${decision.fallbackUsed ? "YES" : "NO"}`,
2351
+ `Time: ${decision.decisionTimeMs}ms`
2352
+ );
2353
+ return { decision, explanation: lines.join("\n") };
2354
+ }
2355
+ };
2356
+
2357
+ // src/timeSeriesAggregator.ts
2358
+ var DEFAULT_TSA_CONFIG = {
2359
+ windowSizeMs: 6e4,
2360
+ // 1 minute
2361
+ windowType: "tumbling",
2362
+ maxWindows: 60,
2363
+ // Keep 1 hour of 1-min windows
2364
+ maxValuesPerWindow: 1e4
2365
+ };
2366
+ function percentile(sorted, p) {
2367
+ if (sorted.length === 0) return 0;
2368
+ if (sorted.length === 1) return sorted[0];
2369
+ const idx = p / 100 * (sorted.length - 1);
2370
+ const lower = Math.floor(idx);
2371
+ const upper = Math.ceil(idx);
2372
+ if (lower === upper) return sorted[lower];
2373
+ return sorted[lower] + (sorted[upper] - sorted[lower]) * (idx - lower);
2374
+ }
2375
+ var TimeSeriesAggregator = class {
2376
+ windows = /* @__PURE__ */ new Map();
2377
+ closedResults = [];
2378
+ config;
2379
+ totalDedups = 0;
2380
+ constructor(config) {
2381
+ this.config = { ...DEFAULT_TSA_CONFIG, ...config };
2382
+ }
2383
+ /**
2384
+ * Ingest a data point (idempotent — duplicates are rejected)
2385
+ */
2386
+ async ingest(point) {
2387
+ const windowId = this.getWindowId(point.timestamp);
2388
+ let window = this.windows.get(windowId);
2389
+ if (!window) {
2390
+ window = this.createWindow(windowId, point.timestamp);
2391
+ this.windows.set(windowId, window);
2392
+ this.evictOldWindows();
2393
+ }
2394
+ if (window.seenIds.has(point.id)) {
2395
+ this.totalDedups++;
2396
+ return { accepted: false, windowId, duplicate: true };
2397
+ }
2398
+ window.seenIds.add(point.id);
2399
+ window.count++;
2400
+ window.sum += point.value;
2401
+ window.min = Math.min(window.min, point.value);
2402
+ window.max = Math.max(window.max, point.value);
2403
+ if (window.values.length < this.config.maxValuesPerWindow) {
2404
+ window.values.push(point.value);
2405
+ }
2406
+ return { accepted: true, windowId, duplicate: false };
2407
+ }
2408
+ /**
2409
+ * Ingest multiple points (batch)
2410
+ */
2411
+ async ingestBatch(points) {
2412
+ let accepted = 0;
2413
+ let duplicates = 0;
2414
+ let errors = 0;
2415
+ for (const point of points) {
2416
+ try {
2417
+ const result = await this.ingest(point);
2418
+ if (result.accepted) accepted++;
2419
+ if (result.duplicate) duplicates++;
2420
+ } catch {
2421
+ errors++;
2422
+ }
2423
+ }
2424
+ return { accepted, duplicates, errors };
2425
+ }
2426
+ /**
2427
+ * Get aggregation result for a specific window
2428
+ */
2429
+ getWindowResult(windowId) {
2430
+ const window = this.windows.get(windowId);
2431
+ if (!window) {
2432
+ return this.closedResults.find((r) => r.windowId === windowId) ?? null;
2433
+ }
2434
+ return this.computeResult(window);
2435
+ }
2436
+ /**
2437
+ * Get current (latest) window result
2438
+ */
2439
+ getCurrentResult() {
2440
+ const now = Date.now();
2441
+ const windowId = this.getWindowId(now);
2442
+ return this.getWindowResult(windowId);
2443
+ }
2444
+ /**
2445
+ * Get results for a time range
2446
+ */
2447
+ getResultsInRange(startMs, endMs) {
2448
+ const results = [];
2449
+ for (const window of this.windows.values()) {
2450
+ if (window.startMs >= startMs && window.endMs <= endMs) {
2451
+ results.push(this.computeResult(window));
2452
+ }
2453
+ }
2454
+ for (const result of this.closedResults) {
2455
+ if (result.startMs >= startMs && result.endMs <= endMs) {
2456
+ if (!results.find((r) => r.windowId === result.windowId)) {
2457
+ results.push(result);
2458
+ }
2459
+ }
2460
+ }
2461
+ return results.sort((a, b) => a.startMs - b.startMs);
2462
+ }
2463
+ /**
2464
+ * Close current window and emit result
2465
+ */
2466
+ async closeWindow(windowId) {
2467
+ const window = this.windows.get(windowId);
2468
+ if (!window) return null;
2469
+ const result = this.computeResult(window);
2470
+ this.closedResults.push(result);
2471
+ this.windows.delete(windowId);
2472
+ if (this.closedResults.length > this.config.maxWindows * 2) {
2473
+ this.closedResults = this.closedResults.slice(-this.config.maxWindows);
2474
+ }
2475
+ if (this.config.onWindowClosed) {
2476
+ try {
2477
+ await this.config.onWindowClosed(result);
2478
+ } catch {
2479
+ }
2480
+ }
2481
+ if (this.config.onAudit) {
2482
+ try {
2483
+ await this.config.onAudit({
2484
+ type: "window_closed",
2485
+ data: {
2486
+ windowId,
2487
+ count: result.metrics.count,
2488
+ avg: result.metrics.avg,
2489
+ p95: result.metrics.p95,
2490
+ dedupCount: result.dedupCount
2491
+ }
2492
+ });
2493
+ } catch {
2494
+ }
2495
+ }
2496
+ return result;
2497
+ }
2498
+ /**
2499
+ * Get overall stats
2500
+ */
2501
+ getStats() {
2502
+ let totalDataPoints = 0;
2503
+ for (const w of this.windows.values()) totalDataPoints += w.count;
2504
+ for (const r of this.closedResults) totalDataPoints += r.metrics.count;
2505
+ return {
2506
+ activeWindows: this.windows.size,
2507
+ closedWindows: this.closedResults.length,
2508
+ totalDedups: this.totalDedups,
2509
+ totalDataPoints
2510
+ };
2511
+ }
2512
+ /**
2513
+ * Reset all windows
2514
+ */
2515
+ reset() {
2516
+ this.windows.clear();
2517
+ this.closedResults = [];
2518
+ this.totalDedups = 0;
2519
+ }
2520
+ // ─── Internal ────────────────────────────────────────────────────
2521
+ getWindowId(timestamp) {
2522
+ const windowStart = Math.floor(timestamp / this.config.windowSizeMs) * this.config.windowSizeMs;
2523
+ return `w_${windowStart}`;
2524
+ }
2525
+ createWindow(windowId, timestamp) {
2526
+ const windowStart = Math.floor(timestamp / this.config.windowSizeMs) * this.config.windowSizeMs;
2527
+ return {
2528
+ windowId,
2529
+ windowType: this.config.windowType,
2530
+ startMs: windowStart,
2531
+ endMs: windowStart + this.config.windowSizeMs,
2532
+ count: 0,
2533
+ sum: 0,
2534
+ min: Infinity,
2535
+ max: -Infinity,
2536
+ values: [],
2537
+ seenIds: /* @__PURE__ */ new Set()
2538
+ };
2539
+ }
2540
+ computeResult(window) {
2541
+ const sorted = [...window.values].sort((a, b) => a - b);
2542
+ const durationSec = (window.endMs - window.startMs) / 1e3;
2543
+ return {
2544
+ windowId: window.windowId,
2545
+ windowType: window.windowType,
2546
+ startMs: window.startMs,
2547
+ endMs: window.endMs,
2548
+ metrics: {
2549
+ count: window.count,
2550
+ sum: window.sum,
2551
+ avg: window.count > 0 ? window.sum / window.count : 0,
2552
+ min: window.min === Infinity ? 0 : window.min,
2553
+ max: window.max === -Infinity ? 0 : window.max,
2554
+ p50: percentile(sorted, 50),
2555
+ p95: percentile(sorted, 95),
2556
+ p99: percentile(sorted, 99),
2557
+ rate: durationSec > 0 ? window.count / durationSec : 0
2558
+ },
2559
+ dedupCount: window.seenIds.size - window.count > 0 ? 0 : this.totalDedups
2560
+ };
2561
+ }
2562
+ evictOldWindows() {
2563
+ if (this.windows.size <= this.config.maxWindows) return;
2564
+ const sorted = Array.from(this.windows.entries()).sort((a, b) => a[1].startMs - b[1].startMs);
2565
+ while (sorted.length > this.config.maxWindows) {
2566
+ const [id, window] = sorted.shift();
2567
+ this.closedResults.push(this.computeResult(window));
2568
+ this.windows.delete(id);
2569
+ }
2570
+ }
2571
+ };
2572
+
2573
+ // src/valuationModel.ts
2574
+ var ValuationModel = class {
2575
+ config;
2576
+ constructor(config) {
2577
+ this.config = config ?? {};
2578
+ }
2579
+ /**
2580
+ * Calculate TAM/SAM/SOM
2581
+ */
2582
+ calculateMarketSize(input) {
2583
+ return {
2584
+ tam: input.totalMarketUsd,
2585
+ sam: input.totalMarketUsd * input.serviceablePercent,
2586
+ som: input.totalMarketUsd * input.serviceablePercent * input.obtainablePercent,
2587
+ year: input.year,
2588
+ growthRate: input.growthRate,
2589
+ assumptions: input.assumptions
2590
+ };
2591
+ }
2592
+ /**
2593
+ * Calculate Unit Economics
2594
+ */
2595
+ calculateUnitEconomics(input) {
2596
+ const netChurn = input.churnRate - input.expansionRate;
2597
+ const effectiveChurn = Math.max(netChurn, 1e-3);
2598
+ const ltv = input.arpu * input.grossMargin / effectiveChurn;
2599
+ const paybackMonths = input.cac / (input.arpu * input.grossMargin);
2600
+ return {
2601
+ arpu: input.arpu,
2602
+ cac: input.cac,
2603
+ ltv: Math.round(ltv * 100) / 100,
2604
+ ltvCacRatio: Math.round(ltv / input.cac * 100) / 100,
2605
+ paybackMonths: Math.round(paybackMonths * 10) / 10,
2606
+ grossMargin: input.grossMargin,
2607
+ churnRate: input.churnRate,
2608
+ expansionRate: input.expansionRate
2609
+ };
2610
+ }
2611
+ /**
2612
+ * DCF Valuation
2613
+ */
2614
+ calculateDCF(input) {
2615
+ const fcfs = [];
2616
+ const discountedFcfs = [];
2617
+ for (let i = 0; i < input.projectedRevenues.length; i++) {
2618
+ const revenue = input.projectedRevenues[i];
2619
+ const operatingIncome = revenue * input.operatingMargin;
2620
+ const afterTax = operatingIncome * (1 - input.taxRate);
2621
+ const capex = revenue * input.capexRatio;
2622
+ const fcf = afterTax - capex;
2623
+ fcfs.push(fcf);
2624
+ const discountFactor = Math.pow(1 + input.discountRate, i + 1);
2625
+ discountedFcfs.push(fcf / discountFactor);
2626
+ }
2627
+ const presentValue = discountedFcfs.reduce((sum, v) => sum + v, 0);
2628
+ const lastFcf = fcfs[fcfs.length - 1] ?? 0;
2629
+ const terminalFcf = lastFcf * (1 + input.terminalGrowthRate);
2630
+ const terminalValue = terminalFcf / (input.discountRate - input.terminalGrowthRate);
2631
+ const discountedTerminal = terminalValue / Math.pow(1 + input.discountRate, input.projectedRevenues.length);
2632
+ const enterpriseValue = presentValue + discountedTerminal;
2633
+ const lastRevenue = input.projectedRevenues[input.projectedRevenues.length - 1] ?? 1;
2634
+ const impliedMultiple = enterpriseValue / lastRevenue;
2635
+ return {
2636
+ presentValue: Math.round(presentValue),
2637
+ terminalValue: Math.round(discountedTerminal),
2638
+ enterpriseValue: Math.round(enterpriseValue),
2639
+ freeCashFlows: fcfs.map((v) => Math.round(v)),
2640
+ discountedCashFlows: discountedFcfs.map((v) => Math.round(v)),
2641
+ impliedMultiple: Math.round(impliedMultiple * 10) / 10
2642
+ };
2643
+ }
2644
+ /**
2645
+ * Comparable Company Valuation
2646
+ */
2647
+ calculateComparable(input) {
2648
+ const revMultiples = input.comparables.map((c) => c.evRevenue);
2649
+ const ebitdaMultiples = input.comparables.map((c) => c.evEbitda);
2650
+ const userValues = input.comparables.map((c) => c.evUser);
2651
+ const medianRevMultiple = this.median(revMultiples);
2652
+ const medianEbitdaMultiple = this.median(ebitdaMultiples);
2653
+ const medianUserValue = this.median(userValues);
2654
+ const revenueVal = input.revenue * medianRevMultiple;
2655
+ const ebitdaVal = input.ebitda * medianEbitdaMultiple;
2656
+ const userVal = input.users * medianUserValue;
2657
+ const avgCompGrowth = input.comparables.reduce((s, c) => s + c.growthRate, 0) / input.comparables.length;
2658
+ const growthPremium = input.growthRate / (avgCompGrowth || 0.1);
2659
+ const growthAdjusted = revenueVal * Math.min(growthPremium, 3);
2660
+ return {
2661
+ revenueMultipleValuation: Math.round(revenueVal),
2662
+ ebitdaMultipleValuation: Math.round(ebitdaVal),
2663
+ perUserValuation: Math.round(userVal),
2664
+ averageValuation: Math.round((revenueVal + ebitdaVal + userVal) / 3),
2665
+ medianMultiple: medianRevMultiple,
2666
+ growthAdjustedValuation: Math.round(growthAdjusted)
2667
+ };
2668
+ }
2669
+ /**
2670
+ * Network Effect Valuation (Metcalfe's Law)
2671
+ */
2672
+ calculateNetworkEffect(input) {
2673
+ const currentValue = Math.pow(input.currentUsers, input.metcalfeExponent) * input.valuePerConnection * input.networkDensity;
2674
+ const projectedValues = input.projectedUsers.map(
2675
+ (users) => Math.pow(users, input.metcalfeExponent) * input.valuePerConnection * input.networkDensity
2676
+ );
2677
+ const metcalfeValue = Math.pow(input.currentUsers, 2) * input.valuePerConnection;
2678
+ const adjustedValue = metcalfeValue * input.networkDensity;
2679
+ return {
2680
+ currentNetworkValue: Math.round(currentValue),
2681
+ projectedValues: projectedValues.map((v) => Math.round(v)),
2682
+ metcalfeValue: Math.round(metcalfeValue),
2683
+ adjustedValue: Math.round(adjustedValue)
2684
+ };
2685
+ }
2686
+ /**
2687
+ * Sensitivity Analysis
2688
+ */
2689
+ runSensitivity(baseInput, variables) {
2690
+ const baseResult = this.calculateDCF(baseInput);
2691
+ const baseCase = baseResult.enterpriseValue;
2692
+ const scenarios = [];
2693
+ const tornado = [];
2694
+ for (const v of variables) {
2695
+ const lowInput = { ...baseInput, [v.field]: v.low };
2696
+ const lowResult = this.calculateDCF(lowInput);
2697
+ const highInput = { ...baseInput, [v.field]: v.high };
2698
+ const highResult = this.calculateDCF(highInput);
2699
+ scenarios.push({
2700
+ name: `${v.name} Low`,
2701
+ value: lowResult.enterpriseValue,
2702
+ delta: (lowResult.enterpriseValue - baseCase) / baseCase * 100,
2703
+ variables: { [v.name]: v.low }
2704
+ });
2705
+ scenarios.push({
2706
+ name: `${v.name} High`,
2707
+ value: highResult.enterpriseValue,
2708
+ delta: (highResult.enterpriseValue - baseCase) / baseCase * 100,
2709
+ variables: { [v.name]: v.high }
2710
+ });
2711
+ tornado.push({
2712
+ variable: v.name,
2713
+ lowValue: lowResult.enterpriseValue,
2714
+ highValue: highResult.enterpriseValue,
2715
+ range: Math.abs(highResult.enterpriseValue - lowResult.enterpriseValue)
2716
+ });
2717
+ }
2718
+ tornado.sort((a, b) => b.range - a.range);
2719
+ return { baseCase, scenarios, tornado };
2720
+ }
2721
+ // ─── Helpers ─────────────────────────────────────────────────────
2722
+ median(values) {
2723
+ if (values.length === 0) return 0;
2724
+ const sorted = [...values].sort((a, b) => a - b);
2725
+ const mid = Math.floor(sorted.length / 2);
2726
+ return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
2727
+ }
2728
+ };
2729
+
2730
+ // src/governanceEnhancer.ts
2731
+ var DEFAULT_GE_CONFIG = {
2732
+ circuitBreakerThreshold: 5,
2733
+ circuitBreakerTimeoutMs: 3e4,
2734
+ halfOpenSuccessThreshold: 3,
2735
+ degradationChain: [
2736
+ {
2737
+ id: "full",
2738
+ name: "Full Capability",
2739
+ order: 4,
2740
+ capabilities: ["all"],
2741
+ restrictions: []
2742
+ },
2743
+ {
2744
+ id: "reduced",
2745
+ name: "Reduced Capability",
2746
+ order: 3,
2747
+ capabilities: ["read", "compute", "cache"],
2748
+ restrictions: ["write", "external_api"]
2749
+ },
2750
+ {
2751
+ id: "minimal",
2752
+ name: "Minimal Capability",
2753
+ order: 2,
2754
+ capabilities: ["read", "cache"],
2755
+ restrictions: ["write", "compute", "external_api"]
2756
+ },
2757
+ {
2758
+ id: "readonly",
2759
+ name: "Read-Only Mode",
2760
+ order: 1,
2761
+ capabilities: ["read"],
2762
+ restrictions: ["write", "compute", "external_api", "cache"]
2763
+ }
2764
+ ],
2765
+ maxPolicyVersions: 10
2766
+ };
2767
+ function simpleHash2(input) {
2768
+ let hash = 0;
2769
+ for (let i = 0; i < input.length; i++) {
2770
+ hash = (hash << 5) - hash + input.charCodeAt(i);
2771
+ hash = hash & hash;
2772
+ }
2773
+ return Math.abs(hash).toString(16).padStart(8, "0");
2774
+ }
2775
+ var GovernanceEnhancer = class {
2776
+ currentPolicy = null;
2777
+ policyHistory = [];
2778
+ circuitBreakers = /* @__PURE__ */ new Map();
2779
+ currentDegradationLevel = "full";
2780
+ config;
2781
+ constructor(config) {
2782
+ this.config = { ...DEFAULT_GE_CONFIG, ...config };
2783
+ }
2784
+ // ─── Policy Hot-Reload ───────────────────────────────────────────
2785
+ /**
2786
+ * Load a new policy version (hot-reload)
2787
+ */
2788
+ async loadPolicy(version, rules) {
2789
+ const hash = simpleHash2(JSON.stringify(rules));
2790
+ const oldVersion = this.currentPolicy?.version;
2791
+ const newPolicy = {
2792
+ version,
2793
+ rules: rules.sort((a, b) => b.priority - a.priority),
2794
+ activatedAt: Date.now(),
2795
+ hash
2796
+ };
2797
+ if (this.currentPolicy) {
2798
+ this.policyHistory.push(this.currentPolicy);
2799
+ if (this.policyHistory.length > this.config.maxPolicyVersions) {
2800
+ this.policyHistory = this.policyHistory.slice(-this.config.maxPolicyVersions);
2801
+ }
2802
+ }
2803
+ this.currentPolicy = newPolicy;
2804
+ if (this.config.onPolicyChange && oldVersion) {
2805
+ try {
2806
+ await this.config.onPolicyChange(oldVersion, version);
2807
+ } catch {
2808
+ }
2809
+ }
2810
+ if (this.config.onAudit) {
2811
+ try {
2812
+ await this.config.onAudit({
2813
+ type: "policy_loaded",
2814
+ data: { version, ruleCount: rules.length, hash, previousVersion: oldVersion }
2815
+ });
2816
+ } catch {
2817
+ }
2818
+ }
2819
+ return { success: true, previousVersion: oldVersion, newVersion: version };
2820
+ }
2821
+ /**
2822
+ * Rollback to a previous policy version
2823
+ */
2824
+ async rollbackPolicy(version) {
2825
+ const target = this.policyHistory.find((p) => p.version === version);
2826
+ if (!target) return false;
2827
+ if (this.currentPolicy) {
2828
+ this.policyHistory.push(this.currentPolicy);
2829
+ }
2830
+ this.currentPolicy = { ...target, activatedAt: Date.now() };
2831
+ return true;
2832
+ }
2833
+ /**
2834
+ * Evaluate a governance decision
2835
+ */
2836
+ async evaluate(context) {
2837
+ if (!this.currentPolicy) {
2838
+ return {
2839
+ allowed: false,
2840
+ action: "deny",
2841
+ reason: "No policy loaded",
2842
+ policyVersion: "none"
2843
+ };
2844
+ }
2845
+ const cbState = this.getCircuitBreakerState(context.resource);
2846
+ if (cbState === "OPEN") {
2847
+ return {
2848
+ allowed: false,
2849
+ action: "deny",
2850
+ circuitState: "OPEN",
2851
+ reason: `Circuit breaker OPEN for ${context.resource}`,
2852
+ policyVersion: this.currentPolicy.version
2853
+ };
2854
+ }
2855
+ for (const rule of this.currentPolicy.rules) {
2856
+ if (!rule.enabled) continue;
2857
+ const matches = this.evaluateCondition(rule.condition, context);
2858
+ if (!matches) continue;
2859
+ const decision = {
2860
+ allowed: rule.action === "allow",
2861
+ action: rule.action,
2862
+ ruleId: rule.id,
2863
+ ruleName: rule.name,
2864
+ circuitState: cbState,
2865
+ policyVersion: this.currentPolicy.version,
2866
+ reason: `Rule ${rule.name} matched: ${rule.action}`
2867
+ };
2868
+ if (rule.action === "degrade" && rule.degradeTo) {
2869
+ decision.degradationLevel = rule.degradeTo;
2870
+ decision.allowed = true;
2871
+ this.currentDegradationLevel = rule.degradeTo;
2872
+ }
2873
+ if (this.config.onAudit) {
2874
+ try {
2875
+ await this.config.onAudit({
2876
+ type: "governance_decision",
2877
+ data: {
2878
+ action: context.action,
2879
+ resource: context.resource,
2880
+ decision: rule.action,
2881
+ ruleId: rule.id,
2882
+ policyVersion: this.currentPolicy.version
2883
+ }
2884
+ });
2885
+ } catch {
2886
+ }
2887
+ }
2888
+ return decision;
2889
+ }
2890
+ return {
2891
+ allowed: true,
2892
+ action: "allow",
2893
+ reason: "No matching rule, default allow",
2894
+ policyVersion: this.currentPolicy.version,
2895
+ circuitState: cbState
2896
+ };
2897
+ }
2898
+ // ─── Circuit Breaker ─────────────────────────────────────────────
2899
+ /**
2900
+ * Record a success for circuit breaker
2901
+ */
2902
+ recordSuccess(resource) {
2903
+ const cb = this.getOrCreateCircuitBreaker(resource);
2904
+ cb.successCount++;
2905
+ cb.lastSuccessAt = Date.now();
2906
+ if (cb.state === "HALF_OPEN") {
2907
+ if (cb.successCount >= this.config.halfOpenSuccessThreshold) {
2908
+ cb.state = "CLOSED";
2909
+ cb.failureCount = 0;
2910
+ cb.halfOpenAttempts = 0;
2911
+ }
2912
+ }
2913
+ }
2914
+ /**
2915
+ * Record a failure for circuit breaker
2916
+ */
2917
+ recordFailure(resource) {
2918
+ const cb = this.getOrCreateCircuitBreaker(resource);
2919
+ cb.failureCount++;
2920
+ cb.lastFailureAt = Date.now();
2921
+ if (cb.state === "CLOSED" && cb.failureCount >= this.config.circuitBreakerThreshold) {
2922
+ cb.state = "OPEN";
2923
+ cb.openedAt = Date.now();
2924
+ } else if (cb.state === "HALF_OPEN") {
2925
+ cb.state = "OPEN";
2926
+ cb.openedAt = Date.now();
2927
+ cb.halfOpenAttempts++;
2928
+ }
2929
+ }
2930
+ /**
2931
+ * Get circuit breaker state for a resource
2932
+ */
2933
+ getCircuitBreakerState(resource) {
2934
+ const cb = this.circuitBreakers.get(resource);
2935
+ if (!cb) return "CLOSED";
2936
+ if (cb.state === "OPEN") {
2937
+ const elapsed = Date.now() - cb.openedAt;
2938
+ if (elapsed >= this.config.circuitBreakerTimeoutMs) {
2939
+ cb.state = "HALF_OPEN";
2940
+ cb.successCount = 0;
2941
+ }
2942
+ }
2943
+ return cb.state;
2944
+ }
2945
+ // ─── Degradation Chain ───────────────────────────────────────────
2946
+ /**
2947
+ * Get current degradation level
2948
+ */
2949
+ getCurrentDegradationLevel() {
2950
+ return this.config.degradationChain.find((d) => d.id === this.currentDegradationLevel);
2951
+ }
2952
+ /**
2953
+ * Degrade to next level
2954
+ */
2955
+ degradeOneLevel() {
2956
+ const current = this.config.degradationChain.find((d) => d.id === this.currentDegradationLevel);
2957
+ if (!current) return null;
2958
+ const nextLevel = this.config.degradationChain.filter((d) => d.order < current.order).sort((a, b) => b.order - a.order)[0];
2959
+ if (nextLevel) {
2960
+ this.currentDegradationLevel = nextLevel.id;
2961
+ return nextLevel;
2962
+ }
2963
+ return null;
2964
+ }
2965
+ /**
2966
+ * Restore to full capability
2967
+ */
2968
+ restoreFullCapability() {
2969
+ this.currentDegradationLevel = "full";
2970
+ }
2971
+ /**
2972
+ * Check if a capability is available at current degradation level
2973
+ */
2974
+ isCapabilityAvailable(capability) {
2975
+ const level = this.getCurrentDegradationLevel();
2976
+ if (!level) return false;
2977
+ return level.capabilities.includes("all") || level.capabilities.includes(capability);
2978
+ }
2979
+ // ─── Status ──────────────────────────────────────────────────────
2980
+ /**
2981
+ * Get full governance status
2982
+ */
2983
+ getStatus() {
2984
+ return {
2985
+ policyVersion: this.currentPolicy?.version ?? null,
2986
+ ruleCount: this.currentPolicy?.rules.length ?? 0,
2987
+ degradationLevel: this.currentDegradationLevel,
2988
+ circuitBreakers: Array.from(this.circuitBreakers.values()),
2989
+ policyHistoryCount: this.policyHistory.length
2990
+ };
2991
+ }
2992
+ // ─── Internal ────────────────────────────────────────────────────
2993
+ evaluateCondition(condition, context) {
2994
+ if (condition === "*") return true;
2995
+ if (condition.startsWith("action:")) {
2996
+ return context.action === condition.substring(7);
2997
+ }
2998
+ if (condition.startsWith("resource:")) {
2999
+ return context.resource.includes(condition.substring(9));
3000
+ }
3001
+ if (condition.startsWith("agent:")) {
3002
+ return context.agentId === condition.substring(6);
3003
+ }
3004
+ return false;
3005
+ }
3006
+ getOrCreateCircuitBreaker(resource) {
3007
+ let cb = this.circuitBreakers.get(resource);
3008
+ if (!cb) {
3009
+ cb = {
3010
+ name: resource,
3011
+ state: "CLOSED",
3012
+ failureCount: 0,
3013
+ successCount: 0,
3014
+ lastFailureAt: 0,
3015
+ lastSuccessAt: 0,
3016
+ openedAt: 0,
3017
+ halfOpenAttempts: 0
3018
+ };
3019
+ this.circuitBreakers.set(resource, cb);
3020
+ }
3021
+ return cb;
3022
+ }
3023
+ };
3024
+
3025
+ // src/contextAccelerator.ts
3026
+ var DEFAULT_CA_CONFIG = {
3027
+ maxCacheEntries: 500,
3028
+ defaultTtlMs: 3e5,
3029
+ // 5 minutes
3030
+ tokenBudget: 8e3,
3031
+ compressionTarget: 0.5,
3032
+ priorityWeights: {
3033
+ critical: 100,
3034
+ high: 75,
3035
+ medium: 50,
3036
+ low: 25
3037
+ }
3038
+ };
3039
+ function estimateTokens(text) {
3040
+ return Math.ceil(text.length / 3.5);
3041
+ }
3042
+ function defaultCompressor(content, targetTokens) {
3043
+ const currentTokens = estimateTokens(content);
3044
+ if (currentTokens <= targetTokens) return content;
3045
+ const ratio = targetTokens / currentTokens;
3046
+ const targetLength = Math.floor(content.length * ratio);
3047
+ if (targetLength < 50) return content.substring(0, 50) + "...";
3048
+ return content.substring(0, targetLength) + "...[compressed]";
3049
+ }
3050
+ var ContextAccelerator = class {
3051
+ cache = /* @__PURE__ */ new Map();
3052
+ prefetchRules = /* @__PURE__ */ new Map();
3053
+ config;
3054
+ stats = {
3055
+ totalHits: 0,
3056
+ totalMisses: 0,
3057
+ totalEvictions: 0,
3058
+ totalCompressions: 0,
3059
+ totalAssemblies: 0
3060
+ };
3061
+ constructor(config) {
3062
+ this.config = { ...DEFAULT_CA_CONFIG, ...config };
3063
+ }
3064
+ /**
3065
+ * Put a fragment into cache
3066
+ */
3067
+ put(fragment) {
3068
+ this.evictExpired();
3069
+ if (this.cache.size >= this.config.maxCacheEntries) {
3070
+ this.evictLRU();
3071
+ }
3072
+ this.cache.set(fragment.id, {
3073
+ fragment,
3074
+ accessCount: 0,
3075
+ lastAccessedAt: Date.now(),
3076
+ createdAt: Date.now(),
3077
+ expiresAt: Date.now() + (fragment.ttlMs || this.config.defaultTtlMs)
3078
+ });
3079
+ }
3080
+ /**
3081
+ * Get a fragment from cache
3082
+ */
3083
+ get(id) {
3084
+ const entry = this.cache.get(id);
3085
+ if (!entry) {
3086
+ this.stats.totalMisses++;
3087
+ return null;
3088
+ }
3089
+ if (Date.now() > entry.expiresAt) {
3090
+ this.cache.delete(id);
3091
+ this.stats.totalMisses++;
3092
+ return null;
3093
+ }
3094
+ entry.accessCount++;
3095
+ entry.lastAccessedAt = Date.now();
3096
+ this.stats.totalHits++;
3097
+ return entry.fragment;
3098
+ }
3099
+ /**
3100
+ * Assemble context from fragments within token budget
3101
+ */
3102
+ async assemble(fragmentIds, additionalFragments, budgetOverride) {
3103
+ const startTime = Date.now();
3104
+ const budget = budgetOverride ?? this.config.tokenBudget;
3105
+ let cacheHits = 0;
3106
+ let cacheMisses = 0;
3107
+ const allFragments = [];
3108
+ for (const id of fragmentIds) {
3109
+ const fragment = this.get(id);
3110
+ if (fragment) {
3111
+ allFragments.push(fragment);
3112
+ cacheHits++;
3113
+ } else {
3114
+ cacheMisses++;
3115
+ }
3116
+ }
3117
+ if (additionalFragments) {
3118
+ allFragments.push(...additionalFragments);
3119
+ }
3120
+ const weights = this.config.priorityWeights;
3121
+ allFragments.sort((a, b) => {
3122
+ const wDiff = (weights[b.priority] ?? 0) - (weights[a.priority] ?? 0);
3123
+ if (wDiff !== 0) return wDiff;
3124
+ return b.timestamp - a.timestamp;
3125
+ });
3126
+ const selected = [];
3127
+ let totalTokens = 0;
3128
+ let droppedCount = 0;
3129
+ let compressedCount = 0;
3130
+ for (const fragment of allFragments) {
3131
+ if (totalTokens >= budget) {
3132
+ droppedCount++;
3133
+ continue;
3134
+ }
3135
+ const remaining = budget - totalTokens;
3136
+ if (fragment.tokenCount <= remaining) {
3137
+ selected.push(fragment);
3138
+ totalTokens += fragment.tokenCount;
3139
+ } else if (fragment.priority === "critical" || fragment.priority === "high") {
3140
+ const compressor = this.config.compressor ?? defaultCompressor;
3141
+ const compressed = compressor(fragment.content, remaining);
3142
+ const compressedTokens = estimateTokens(compressed);
3143
+ selected.push({
3144
+ ...fragment,
3145
+ content: compressed,
3146
+ tokenCount: compressedTokens,
3147
+ compressed: true
3148
+ });
3149
+ totalTokens += compressedTokens;
3150
+ compressedCount++;
3151
+ this.stats.totalCompressions++;
3152
+ } else {
3153
+ droppedCount++;
3154
+ }
3155
+ }
3156
+ this.stats.totalAssemblies++;
3157
+ const result = {
3158
+ fragments: selected,
3159
+ totalTokens,
3160
+ budgetUsed: budget > 0 ? totalTokens / budget : 0,
3161
+ droppedCount,
3162
+ compressedCount,
3163
+ cacheHits,
3164
+ cacheMisses,
3165
+ assemblyTimeMs: Date.now() - startTime
3166
+ };
3167
+ if (this.config.onAudit) {
3168
+ try {
3169
+ await this.config.onAudit({
3170
+ type: "context_assembled",
3171
+ data: {
3172
+ totalTokens,
3173
+ budgetUsed: result.budgetUsed,
3174
+ fragmentCount: selected.length,
3175
+ droppedCount,
3176
+ compressedCount,
3177
+ cacheHits,
3178
+ cacheMisses,
3179
+ assemblyTimeMs: result.assemblyTimeMs
3180
+ }
3181
+ });
3182
+ } catch {
3183
+ }
3184
+ }
3185
+ return result;
3186
+ }
3187
+ /**
3188
+ * Register a prefetch rule
3189
+ */
3190
+ addPrefetchRule(rule) {
3191
+ this.prefetchRules.set(rule.id, rule);
3192
+ }
3193
+ /**
3194
+ * Execute prefetch based on task type
3195
+ */
3196
+ async prefetch(taskType, fragmentLoader) {
3197
+ const matchingRules = Array.from(this.prefetchRules.values()).filter(
3198
+ (r) => r.enabled && taskType.includes(r.trigger)
3199
+ );
3200
+ if (matchingRules.length === 0) return 0;
3201
+ const idsToFetch = /* @__PURE__ */ new Set();
3202
+ for (const rule of matchingRules) {
3203
+ for (const id of rule.fragmentIds) {
3204
+ if (!this.cache.has(id)) {
3205
+ idsToFetch.add(id);
3206
+ }
3207
+ }
3208
+ }
3209
+ if (idsToFetch.size === 0) return 0;
3210
+ const fragments = await fragmentLoader(Array.from(idsToFetch));
3211
+ for (const f of fragments) {
3212
+ this.put(f);
3213
+ }
3214
+ return fragments.length;
3215
+ }
3216
+ /**
3217
+ * Invalidate cache entries
3218
+ */
3219
+ invalidate(ids) {
3220
+ let count = 0;
3221
+ for (const id of ids) {
3222
+ if (this.cache.delete(id)) count++;
3223
+ }
3224
+ return count;
3225
+ }
3226
+ /**
3227
+ * Get cache stats
3228
+ */
3229
+ getStats() {
3230
+ const total = this.stats.totalHits + this.stats.totalMisses;
3231
+ return {
3232
+ cacheSize: this.cache.size,
3233
+ maxSize: this.config.maxCacheEntries,
3234
+ hitRate: total > 0 ? this.stats.totalHits / total : 0,
3235
+ ...this.stats,
3236
+ prefetchRuleCount: this.prefetchRules.size
3237
+ };
3238
+ }
3239
+ /**
3240
+ * Clear all cache
3241
+ */
3242
+ clear() {
3243
+ this.cache.clear();
3244
+ }
3245
+ // ─── Internal ────────────────────────────────────────────────────
3246
+ evictExpired() {
3247
+ const now = Date.now();
3248
+ for (const [id, entry] of this.cache) {
3249
+ if (now > entry.expiresAt) {
3250
+ this.cache.delete(id);
3251
+ this.stats.totalEvictions++;
3252
+ }
3253
+ }
3254
+ }
3255
+ evictLRU() {
3256
+ let oldestId = null;
3257
+ let oldestAccess = Infinity;
3258
+ for (const [id, entry] of this.cache) {
3259
+ if (entry.lastAccessedAt < oldestAccess) {
3260
+ oldestAccess = entry.lastAccessedAt;
3261
+ oldestId = id;
3262
+ }
3263
+ }
3264
+ if (oldestId) {
3265
+ this.cache.delete(oldestId);
3266
+ this.stats.totalEvictions++;
3267
+ }
3268
+ }
3269
+ };
3270
+
3271
+ // src/trendAlertEngine.ts
3272
+ var DEFAULT_THRESHOLDS2 = [
3273
+ {
3274
+ alert_type: "BLOCK_RATE_SURGE",
3275
+ metric_name: "block_rate",
3276
+ baseline_window_hours: 24,
3277
+ surge_multiplier: 2,
3278
+ absolute_threshold: 0.5,
3279
+ severity: "CRITICAL",
3280
+ protective_actions: ["TIGHTEN_THRESHOLD", "NOTIFY_ONLY"],
3281
+ cooldown_seconds: 300,
3282
+ enabled: true
3283
+ },
3284
+ {
3285
+ alert_type: "OVERRIDE_RATE_SURGE",
3286
+ metric_name: "override_rate",
3287
+ baseline_window_hours: 24,
3288
+ surge_multiplier: 3,
3289
+ absolute_threshold: 0.3,
3290
+ severity: "CRITICAL",
3291
+ protective_actions: ["TIGHTEN_THRESHOLD", "FORCE_HUMAN_GATE"],
3292
+ cooldown_seconds: 300,
3293
+ enabled: true
3294
+ },
3295
+ {
3296
+ alert_type: "UNKNOWN_REASON_CODE",
3297
+ metric_name: "unknown_reason_rate",
3298
+ baseline_window_hours: 1,
3299
+ surge_multiplier: 1.5,
3300
+ absolute_threshold: 0.1,
3301
+ severity: "WARN",
3302
+ protective_actions: ["NOTIFY_ONLY"],
3303
+ cooldown_seconds: 600,
3304
+ enabled: true
3305
+ },
3306
+ {
3307
+ alert_type: "APPROVAL_QUEUE_BACKLOG",
3308
+ metric_name: "pending_approval_count",
3309
+ baseline_window_hours: 1,
3310
+ surge_multiplier: 5,
3311
+ absolute_threshold: 50,
3312
+ severity: "CRITICAL",
3313
+ protective_actions: ["DEGRADE", "NOTIFY_ONLY"],
3314
+ cooldown_seconds: 180,
3315
+ enabled: true
3316
+ },
3317
+ {
3318
+ alert_type: "CONFIDENCE_DROP",
3319
+ metric_name: "avg_confidence",
3320
+ baseline_window_hours: 24,
3321
+ surge_multiplier: 0.5,
3322
+ // 低于基线的比例
3323
+ absolute_threshold: 0.3,
3324
+ severity: "WARN",
3325
+ protective_actions: ["TIGHTEN_THRESHOLD"],
3326
+ cooldown_seconds: 600,
3327
+ enabled: true
3328
+ },
3329
+ {
3330
+ alert_type: "ERROR_RATE_SURGE",
3331
+ metric_name: "error_rate",
3332
+ baseline_window_hours: 1,
3333
+ surge_multiplier: 3,
3334
+ absolute_threshold: 0.2,
3335
+ severity: "EMERGENCY",
3336
+ protective_actions: ["KILL_SWITCH"],
3337
+ cooldown_seconds: 60,
3338
+ enabled: true
3339
+ }
3340
+ ];
3341
+ var TrendAlertEngine = class {
3342
+ thresholds;
3343
+ alertHistory = [];
3344
+ lastAlertTime = /* @__PURE__ */ new Map();
3345
+ systemState;
3346
+ metricsBuffer = [];
3347
+ constructor(customThresholds) {
3348
+ this.thresholds = customThresholds || DEFAULT_THRESHOLDS2;
3349
+ this.systemState = {
3350
+ kill_switch: { enabled: false, reason: null, enabled_at: null, enabled_by: "system", auto_triggered: false },
3351
+ degrade: { active: false, level: "LIGHT", reason: "", activated_at: null, auto_recover_at: null },
3352
+ tightened_threshold_multiplier: 1,
3353
+ force_human_gate: false
3354
+ };
3355
+ }
3356
+ // ---- 核心: 评估趋势 ----
3357
+ evaluate(metrics, tenantId = "default") {
3358
+ const alerts = [];
3359
+ this.metricsBuffer = metrics;
3360
+ for (const threshold of this.thresholds) {
3361
+ if (!threshold.enabled) continue;
3362
+ const metric = metrics.find((m) => m.metric_name === threshold.metric_name);
3363
+ if (!metric) continue;
3364
+ const lastAlert = this.lastAlertTime.get(threshold.alert_type);
3365
+ if (lastAlert && Date.now() - lastAlert < threshold.cooldown_seconds * 1e3) {
3366
+ continue;
3367
+ }
3368
+ const triggered = this.checkThreshold(metric, threshold);
3369
+ if (!triggered) continue;
3370
+ const surgeRatio = metric.baseline_value > 0 ? metric.current_value / metric.baseline_value : metric.current_value;
3371
+ const alert = {
3372
+ alert_id: `alert_${threshold.alert_type}_${Date.now()}`,
3373
+ alert_type: threshold.alert_type,
3374
+ severity: threshold.severity,
3375
+ metric_name: threshold.metric_name,
3376
+ current_value: metric.current_value,
3377
+ baseline_value: metric.baseline_value,
3378
+ threshold_value: threshold.absolute_threshold,
3379
+ surge_ratio: Math.round(surgeRatio * 100) / 100,
3380
+ protective_actions_taken: [],
3381
+ message: this.formatAlertMessage(threshold, metric, surgeRatio),
3382
+ tenant_id: tenantId,
3383
+ created_at: Date.now(),
3384
+ acknowledged: false,
3385
+ acknowledged_by: null,
3386
+ acknowledged_at: null
3387
+ };
3388
+ for (const action of threshold.protective_actions) {
3389
+ this.executeProtectiveAction(action, alert);
3390
+ alert.protective_actions_taken.push(action);
3391
+ }
3392
+ alerts.push(alert);
3393
+ this.alertHistory.push(alert);
3394
+ this.lastAlertTime.set(threshold.alert_type, Date.now());
3395
+ }
3396
+ return alerts;
3397
+ }
3398
+ // ---- Cron 评估入口 (DegradeEvaluator) ----
3399
+ cronEvaluate(getMetrics, tenantId = "default") {
3400
+ const metrics = getMetrics();
3401
+ const alerts = this.evaluate(metrics, tenantId);
3402
+ this.checkAutoRecover();
3403
+ return { alerts, state: this.getSystemState() };
3404
+ }
3405
+ // ---- 保护动作执行 ----
3406
+ executeProtectiveAction(action, alert) {
3407
+ switch (action) {
3408
+ case "DEGRADE":
3409
+ this.activateDegrade(alert);
3410
+ break;
3411
+ case "TIGHTEN_THRESHOLD":
3412
+ this.tightenThreshold(alert);
3413
+ break;
3414
+ case "KILL_SWITCH":
3415
+ this.activateKillSwitch(alert);
3416
+ break;
3417
+ case "FORCE_HUMAN_GATE":
3418
+ this.systemState.force_human_gate = true;
3419
+ break;
3420
+ case "NOTIFY_ONLY":
3421
+ break;
3422
+ }
3423
+ }
3424
+ activateDegrade(alert) {
3425
+ const level = alert.severity === "EMERGENCY" ? "SEVERE" : alert.severity === "CRITICAL" ? "MODERATE" : "LIGHT";
3426
+ this.systemState.degrade = {
3427
+ active: true,
3428
+ level,
3429
+ reason: `Auto-degrade triggered by ${alert.alert_type}: ${alert.message}`,
3430
+ activated_at: Date.now(),
3431
+ auto_recover_at: Date.now() + 30 * 60 * 1e3
3432
+ // 30分钟后自动恢复
3433
+ };
3434
+ }
3435
+ tightenThreshold(alert) {
3436
+ this.systemState.tightened_threshold_multiplier = Math.min(
3437
+ this.systemState.tightened_threshold_multiplier * 1.2,
3438
+ 2
3439
+ );
3440
+ }
3441
+ activateKillSwitch(alert) {
3442
+ this.systemState.kill_switch = {
3443
+ enabled: true,
3444
+ reason: `Auto Kill-Switch triggered by ${alert.alert_type}: ${alert.message}`,
3445
+ enabled_at: Date.now(),
3446
+ enabled_by: "trend_alert_engine",
3447
+ auto_triggered: true
3448
+ };
3449
+ }
3450
+ // ---- 阈值检查 ----
3451
+ checkThreshold(metric, threshold) {
3452
+ if (threshold.alert_type === "CONFIDENCE_DROP") {
3453
+ return metric.current_value < threshold.absolute_threshold || metric.baseline_value > 0 && metric.current_value < metric.baseline_value * threshold.surge_multiplier;
3454
+ }
3455
+ if (threshold.alert_type === "APPROVAL_QUEUE_BACKLOG") {
3456
+ return metric.current_value > threshold.absolute_threshold;
3457
+ }
3458
+ const surgeTriggered = metric.baseline_value > 0 && metric.current_value > metric.baseline_value * threshold.surge_multiplier;
3459
+ const absoluteTriggered = metric.current_value > threshold.absolute_threshold;
3460
+ return surgeTriggered || absoluteTriggered;
3461
+ }
3462
+ // ---- 自动恢复 ----
3463
+ checkAutoRecover() {
3464
+ if (this.systemState.degrade.active && this.systemState.degrade.auto_recover_at) {
3465
+ if (Date.now() >= this.systemState.degrade.auto_recover_at) {
3466
+ this.systemState.degrade = {
3467
+ active: false,
3468
+ level: "LIGHT",
3469
+ reason: "Auto-recovered after cooldown",
3470
+ activated_at: null,
3471
+ auto_recover_at: null
3472
+ };
3473
+ }
3474
+ }
3475
+ }
3476
+ // ---- 手动操作 ----
3477
+ acknowledgeAlert(alertId, acknowledgedBy) {
3478
+ const alert = this.alertHistory.find((a) => a.alert_id === alertId);
3479
+ if (!alert) return false;
3480
+ alert.acknowledged = true;
3481
+ alert.acknowledged_by = acknowledgedBy;
3482
+ alert.acknowledged_at = Date.now();
3483
+ return true;
3484
+ }
3485
+ disableKillSwitch(reason, actor) {
3486
+ if (!this.systemState.kill_switch.enabled) return false;
3487
+ this.systemState.kill_switch = {
3488
+ enabled: false,
3489
+ reason: `Disabled by ${actor}: ${reason}`,
3490
+ enabled_at: null,
3491
+ enabled_by: actor,
3492
+ auto_triggered: false
3493
+ };
3494
+ return true;
3495
+ }
3496
+ resetDegrade() {
3497
+ this.systemState.degrade = {
3498
+ active: false,
3499
+ level: "LIGHT",
3500
+ reason: "Manual reset",
3501
+ activated_at: null,
3502
+ auto_recover_at: null
3503
+ };
3504
+ this.systemState.tightened_threshold_multiplier = 1;
3505
+ this.systemState.force_human_gate = false;
3506
+ }
3507
+ // ---- 查询 ----
3508
+ getSystemState() {
3509
+ return { ...this.systemState };
3510
+ }
3511
+ getAlertHistory(limit = 50) {
3512
+ return this.alertHistory.slice(-limit);
3513
+ }
3514
+ getActiveAlerts() {
3515
+ return this.alertHistory.filter((a) => !a.acknowledged);
3516
+ }
3517
+ getMetricsBuffer() {
3518
+ return [...this.metricsBuffer];
3519
+ }
3520
+ // ---- 辅助 ----
3521
+ formatAlertMessage(threshold, metric, surgeRatio) {
3522
+ return `[${threshold.severity}] ${threshold.alert_type}: ${metric.metric_name} = ${metric.current_value.toFixed(3)} (baseline: ${metric.baseline_value.toFixed(3)}, surge: ${surgeRatio.toFixed(1)}x, threshold: ${threshold.absolute_threshold})`;
3523
+ }
3524
+ };
3525
+
3526
+ // src/selfConstraintEngine.ts
3527
+ var DEFAULT_THRESHOLDS3 = {
3528
+ risk_density: 0.75,
3529
+ conflict_rate: 0.6,
3530
+ confidence_drop: 0.2,
3531
+ error_rate: 0.15,
3532
+ latency_p99_ms: 5e3,
3533
+ consecutive_failures: 5
3534
+ };
3535
+ var NORMAL_FLAGS = {
3536
+ enable_advanced_features: true,
3537
+ enable_auto_approve: true,
3538
+ enable_batch_operations: true,
3539
+ enable_external_api_calls: true,
3540
+ enable_write_operations: true,
3541
+ require_human_gate: false,
3542
+ require_dual_review: false,
3543
+ max_concurrent_decisions: 100,
3544
+ decision_delay_ms: 0
3545
+ };
3546
+ var CAUTIOUS_FLAGS = {
3547
+ enable_advanced_features: true,
3548
+ enable_auto_approve: false,
3549
+ // 关闭自动审批
3550
+ enable_batch_operations: true,
3551
+ enable_external_api_calls: true,
3552
+ enable_write_operations: true,
3553
+ require_human_gate: false,
3554
+ require_dual_review: false,
3555
+ max_concurrent_decisions: 50,
3556
+ decision_delay_ms: 500
3557
+ // 500ms 延迟
3558
+ };
3559
+ var RESTRICTED_FLAGS = {
3560
+ enable_advanced_features: false,
3561
+ // 关闭高级功能
3562
+ enable_auto_approve: false,
3563
+ enable_batch_operations: false,
3564
+ // 关闭批量操作
3565
+ enable_external_api_calls: true,
3566
+ enable_write_operations: true,
3567
+ require_human_gate: true,
3568
+ // 强制人工门禁
3569
+ require_dual_review: false,
3570
+ max_concurrent_decisions: 10,
3571
+ decision_delay_ms: 2e3
3572
+ // 2s 延迟
3573
+ };
3574
+ var LOCKDOWN_FLAGS = {
3575
+ enable_advanced_features: false,
3576
+ enable_auto_approve: false,
3577
+ enable_batch_operations: false,
3578
+ enable_external_api_calls: false,
3579
+ // 关闭外部调用
3580
+ enable_write_operations: false,
3581
+ // 关闭写操作
3582
+ require_human_gate: true,
3583
+ require_dual_review: true,
3584
+ // 双人审核
3585
+ max_concurrent_decisions: 1,
3586
+ decision_delay_ms: 5e3
3587
+ // 5s 延迟
3588
+ };
3589
+ var LEVEL_FLAGS_MAP = {
3590
+ NORMAL: NORMAL_FLAGS,
3591
+ CAUTIOUS: CAUTIOUS_FLAGS,
3592
+ RESTRICTED: RESTRICTED_FLAGS,
3593
+ LOCKDOWN: LOCKDOWN_FLAGS
3594
+ };
3595
+ var SelfConstraintEngine = class {
3596
+ config;
3597
+ state;
3598
+ constructor(config) {
3599
+ this.config = {
3600
+ thresholds: config?.thresholds || DEFAULT_THRESHOLDS3,
3601
+ flags: config?.flags || NORMAL_FLAGS,
3602
+ auto_recover_after_minutes: config?.auto_recover_after_minutes || 30,
3603
+ evaluation_interval_seconds: config?.evaluation_interval_seconds || 60
3604
+ };
3605
+ this.state = {
3606
+ current_level: "NORMAL",
3607
+ active_modes: [],
3608
+ flags: { ...NORMAL_FLAGS },
3609
+ activated_at: null,
3610
+ auto_recover_at: null,
3611
+ last_evaluation_at: 0,
3612
+ evaluation_count: 0,
3613
+ constraint_history: []
3614
+ };
3615
+ }
3616
+ // ---- 核心: 评估自我约束 ----
3617
+ evaluate(metrics) {
3618
+ const triggers = [];
3619
+ const modes = /* @__PURE__ */ new Set();
3620
+ triggers.push({
3621
+ metric_name: "risk_density",
3622
+ current_value: metrics.risk_density,
3623
+ threshold_value: this.config.thresholds.risk_density,
3624
+ exceeded: metrics.risk_density >= this.config.thresholds.risk_density
3625
+ });
3626
+ if (metrics.risk_density >= this.config.thresholds.risk_density) {
3627
+ modes.add("CAPABILITY_DOWN");
3628
+ modes.add("PERMISSION_DOWN");
3629
+ }
3630
+ triggers.push({
3631
+ metric_name: "conflict_rate",
3632
+ current_value: metrics.conflict_rate,
3633
+ threshold_value: this.config.thresholds.conflict_rate,
3634
+ exceeded: metrics.conflict_rate >= this.config.thresholds.conflict_rate
3635
+ });
3636
+ if (metrics.conflict_rate >= this.config.thresholds.conflict_rate) {
3637
+ modes.add("SPEED_DOWN");
3638
+ modes.add("PERMISSION_DOWN");
3639
+ }
3640
+ const confidenceDrop = metrics.prev_avg_confidence > 0 ? (metrics.prev_avg_confidence - metrics.avg_confidence) / metrics.prev_avg_confidence : 0;
3641
+ triggers.push({
3642
+ metric_name: "confidence_drop",
3643
+ current_value: confidenceDrop,
3644
+ threshold_value: this.config.thresholds.confidence_drop,
3645
+ exceeded: confidenceDrop >= this.config.thresholds.confidence_drop
3646
+ });
3647
+ if (confidenceDrop >= this.config.thresholds.confidence_drop) {
3648
+ modes.add("SPEED_DOWN");
3649
+ }
3650
+ triggers.push({
3651
+ metric_name: "error_rate",
3652
+ current_value: metrics.error_rate,
3653
+ threshold_value: this.config.thresholds.error_rate,
3654
+ exceeded: metrics.error_rate >= this.config.thresholds.error_rate
3655
+ });
3656
+ if (metrics.error_rate >= this.config.thresholds.error_rate) {
3657
+ modes.add("CAPABILITY_DOWN");
3658
+ }
3659
+ triggers.push({
3660
+ metric_name: "latency_p99_ms",
3661
+ current_value: metrics.latency_p99_ms,
3662
+ threshold_value: this.config.thresholds.latency_p99_ms,
3663
+ exceeded: metrics.latency_p99_ms >= this.config.thresholds.latency_p99_ms
3664
+ });
3665
+ if (metrics.latency_p99_ms >= this.config.thresholds.latency_p99_ms) {
3666
+ modes.add("SPEED_DOWN");
3667
+ }
3668
+ triggers.push({
3669
+ metric_name: "consecutive_failures",
3670
+ current_value: metrics.consecutive_failures,
3671
+ threshold_value: this.config.thresholds.consecutive_failures,
3672
+ exceeded: metrics.consecutive_failures >= this.config.thresholds.consecutive_failures
3673
+ });
3674
+ if (metrics.consecutive_failures >= this.config.thresholds.consecutive_failures) {
3675
+ modes.add("CAPABILITY_DOWN");
3676
+ modes.add("PERMISSION_DOWN");
3677
+ }
3678
+ const triggeredCount = triggers.filter((t) => t.exceeded).length;
3679
+ const level = this.calculateLevel(triggeredCount, metrics.system_pressure);
3680
+ const activeModes = Array.from(modes);
3681
+ const flagsApplied = LEVEL_FLAGS_MAP[level];
3682
+ this.applyConstraint(level, activeModes, flagsApplied);
3683
+ const decision = {
3684
+ decision_id: `sc_${Date.now()}_${this.state.evaluation_count}`,
3685
+ timestamp: Date.now(),
3686
+ level,
3687
+ modes_activated: activeModes,
3688
+ triggers,
3689
+ flags_applied: flagsApplied,
3690
+ reason_code: activeModes.length > 0 ? "SELF_CONSTRAINT_ACTIVATED" : "NORMAL",
3691
+ auto_recover_at: level !== "NORMAL" ? Date.now() + this.config.auto_recover_after_minutes * 60 * 1e3 : null
3692
+ };
3693
+ this.state.constraint_history.push(decision);
3694
+ if (this.state.constraint_history.length > 100) {
3695
+ this.state.constraint_history = this.state.constraint_history.slice(-100);
3696
+ }
3697
+ this.state.evaluation_count++;
3698
+ this.state.last_evaluation_at = Date.now();
3699
+ return decision;
3700
+ }
3701
+ // ---- 约束级别计算 ----
3702
+ calculateLevel(triggeredCount, systemPressure) {
3703
+ const score = triggeredCount + systemPressure * 3;
3704
+ if (score >= 5) return "LOCKDOWN";
3705
+ if (score >= 3) return "RESTRICTED";
3706
+ if (score >= 1) return "CAUTIOUS";
3707
+ return "NORMAL";
3708
+ }
3709
+ // ---- 应用约束 ----
3710
+ applyConstraint(level, modes, flags) {
3711
+ const wasNormal = this.state.current_level === "NORMAL";
3712
+ this.state.current_level = level;
3713
+ this.state.active_modes = modes;
3714
+ this.state.flags = { ...flags };
3715
+ if (level !== "NORMAL" && wasNormal) {
3716
+ this.state.activated_at = Date.now();
3717
+ this.state.auto_recover_at = Date.now() + this.config.auto_recover_after_minutes * 60 * 1e3;
3718
+ } else if (level === "NORMAL") {
3719
+ this.state.activated_at = null;
3720
+ this.state.auto_recover_at = null;
3721
+ }
3722
+ }
3723
+ // ---- 自动恢复检查 ----
3724
+ checkAutoRecover() {
3725
+ if (this.state.current_level === "NORMAL") return false;
3726
+ if (!this.state.auto_recover_at) return false;
3727
+ if (Date.now() >= this.state.auto_recover_at) {
3728
+ this.reset();
3729
+ return true;
3730
+ }
3731
+ return false;
3732
+ }
3733
+ // ---- 手动操作 ----
3734
+ reset() {
3735
+ this.state.current_level = "NORMAL";
3736
+ this.state.active_modes = [];
3737
+ this.state.flags = { ...NORMAL_FLAGS };
3738
+ this.state.activated_at = null;
3739
+ this.state.auto_recover_at = null;
3740
+ }
3741
+ forceLevel(level) {
3742
+ const flags = LEVEL_FLAGS_MAP[level];
3743
+ this.applyConstraint(level, level === "NORMAL" ? [] : ["CAPABILITY_DOWN", "PERMISSION_DOWN"], flags);
3744
+ }
3745
+ // ---- 决策前检查 (Gate 集成) ----
3746
+ preDecisionCheck(action, resource) {
3747
+ const flags = this.state.flags;
3748
+ if (!flags.enable_write_operations && this.isWriteAction(action)) {
3749
+ return {
3750
+ allowed: false,
3751
+ delay_ms: 0,
3752
+ requires_human: true,
3753
+ requires_dual_review: flags.require_dual_review,
3754
+ reason: `Write operations disabled at ${this.state.current_level} level`
3755
+ };
3756
+ }
3757
+ if (!flags.enable_external_api_calls && this.isExternalAction(action)) {
3758
+ return {
3759
+ allowed: false,
3760
+ delay_ms: 0,
3761
+ requires_human: true,
3762
+ requires_dual_review: flags.require_dual_review,
3763
+ reason: `External API calls disabled at ${this.state.current_level} level`
3764
+ };
3765
+ }
3766
+ if (!flags.enable_batch_operations && this.isBatchAction(action)) {
3767
+ return {
3768
+ allowed: false,
3769
+ delay_ms: 0,
3770
+ requires_human: true,
3771
+ requires_dual_review: false,
3772
+ reason: `Batch operations disabled at ${this.state.current_level} level`
3773
+ };
3774
+ }
3775
+ return {
3776
+ allowed: true,
3777
+ delay_ms: flags.decision_delay_ms,
3778
+ requires_human: flags.require_human_gate,
3779
+ requires_dual_review: flags.require_dual_review,
3780
+ reason: this.state.current_level === "NORMAL" ? "OK" : `Constrained at ${this.state.current_level} level`
3781
+ };
3782
+ }
3783
+ // ---- 查询 ----
3784
+ getState() {
3785
+ return {
3786
+ ...this.state,
3787
+ flags: { ...this.state.flags },
3788
+ active_modes: [...this.state.active_modes],
3789
+ constraint_history: [...this.state.constraint_history]
3790
+ };
3791
+ }
3792
+ getCurrentLevel() {
3793
+ return this.state.current_level;
3794
+ }
3795
+ getFlags() {
3796
+ return { ...this.state.flags };
3797
+ }
3798
+ isConstrained() {
3799
+ return this.state.current_level !== "NORMAL";
3800
+ }
3801
+ // ---- 辅助 ----
3802
+ isWriteAction(action) {
3803
+ const writePatterns = ["write", "create", "update", "delete", "insert", "modify", "patch", "put"];
3804
+ return writePatterns.some((p) => action.toLowerCase().includes(p));
3805
+ }
3806
+ isExternalAction(action) {
3807
+ const externalPatterns = ["external", "api_call", "webhook", "http", "fetch", "request"];
3808
+ return externalPatterns.some((p) => action.toLowerCase().includes(p));
3809
+ }
3810
+ isBatchAction(action) {
3811
+ const batchPatterns = ["batch", "bulk", "mass", "multi"];
3812
+ return batchPatterns.some((p) => action.toLowerCase().includes(p));
3813
+ }
3814
+ };
3815
+
3816
+ // src/contributionSettlement.ts
3817
+ var DEFAULT_SCORE_CONFIG = {
3818
+ version: "1.0.0",
3819
+ weight_risk: 0.35,
3820
+ weight_cost: 0.25,
3821
+ weight_human: 0.2,
3822
+ weight_stability: 0.2,
3823
+ weight_penalty: 1,
3824
+ caps: {
3825
+ max_single_event: 100,
3826
+ max_risk_positive_when_risk_up: false
3827
+ },
3828
+ guardrails: [
3829
+ "RISK_UP_BLOCKS_POSITIVE",
3830
+ "EVIDENCE_DOWNGRADE_NEGATIVE",
3831
+ "OVERRIDE_INCREASE_PENALTY"
3832
+ ],
3833
+ approved_by: "system",
3834
+ approved_at: Date.now()
3835
+ };
3836
+ var MVP_ATTRIBUTION_RULES = [
3837
+ {
3838
+ condition: "RULE_TRIGGERED_BLOCK_WARN",
3839
+ target_entity_type: "rule",
3840
+ target_entity_field: "rule_id",
3841
+ weight: 1
3842
+ },
3843
+ {
3844
+ condition: "EVIDENCE_UPGRADED_ALLOW",
3845
+ target_entity_type: "tool",
3846
+ target_entity_field: "evidence_source",
3847
+ weight: 0.8
3848
+ },
3849
+ {
3850
+ condition: "MODEL_ROUTE_CHEAPER_SAME_RESULT",
3851
+ target_entity_type: "model",
3852
+ target_entity_field: "modelops_route_id",
3853
+ weight: 0.7
3854
+ },
3855
+ {
3856
+ condition: "CACHE_HIT_SKIP_TOOL",
3857
+ target_entity_type: "system",
3858
+ target_entity_field: "context_accelerator",
3859
+ weight: 0.6
3860
+ },
3861
+ {
3862
+ condition: "HUMAN_OVERRIDE_CORRECTION",
3863
+ target_entity_type: "human",
3864
+ target_entity_field: "actor_id",
3865
+ weight: 0.5
3866
+ }
3867
+ ];
3868
+ var BUILTIN_PENALTY_CHECKS = [
3869
+ {
3870
+ name: "OVERRIDE_INCREASE",
3871
+ detect: (_events, ctx) => {
3872
+ if (ctx.override_count_delta > 0) {
3873
+ return ctx.override_count_delta * 5;
3874
+ }
3875
+ return 0;
3876
+ }
3877
+ },
3878
+ {
3879
+ name: "REPLAY_FAIL_INCREASE",
3880
+ detect: (_events, ctx) => {
3881
+ if (ctx.replay_fail_delta > 0) {
3882
+ return ctx.replay_fail_delta * 10;
3883
+ }
3884
+ return 0;
3885
+ }
3886
+ },
3887
+ {
3888
+ name: "RISK_REGRESSION",
3889
+ detect: (_events, ctx) => {
3890
+ if (ctx.risk_regression) {
3891
+ return 50;
3892
+ }
3893
+ return 0;
3894
+ }
3895
+ },
3896
+ {
3897
+ name: "EVIDENCE_DOWNGRADE",
3898
+ detect: (_events, ctx) => {
3899
+ if (ctx.evidence_downgrade) {
3900
+ return 30;
3901
+ }
3902
+ return 0;
3903
+ }
3904
+ },
3905
+ {
3906
+ name: "SELF_MANUFACTURE_DETECT",
3907
+ detect: (events, _ctx) => {
3908
+ const entityMap = /* @__PURE__ */ new Map();
3909
+ for (const e of events) {
3910
+ const key = `${e.entity_type}:${e.entity_id}`;
3911
+ const entry = entityMap.get(key) || { negative: 0, positive: 0 };
3912
+ if (e.delta_value < 0) entry.negative += Math.abs(e.delta_value);
3913
+ else entry.positive += e.delta_value;
3914
+ entityMap.set(key, entry);
3915
+ }
3916
+ let penalty = 0;
3917
+ for (const [, entry] of entityMap) {
3918
+ if (entry.negative > 20 && entry.positive > 20) {
3919
+ const ratio = Math.min(entry.negative, entry.positive) / Math.max(entry.negative, entry.positive);
3920
+ if (ratio > 0.7) {
3921
+ penalty += 25;
3922
+ }
3923
+ }
3924
+ }
3925
+ return penalty;
3926
+ }
3927
+ }
3928
+ ];
3929
+ var ContributionSettlementEngine = class {
3930
+ config;
3931
+ attributionRules;
3932
+ penaltyChecks;
3933
+ eventStore = [];
3934
+ scoreStore = [];
3935
+ constructor(config, customRules, customPenalties) {
3936
+ this.config = { ...DEFAULT_SCORE_CONFIG, ...config };
3937
+ this.attributionRules = customRules || MVP_ATTRIBUTION_RULES;
3938
+ this.penaltyChecks = [...BUILTIN_PENALTY_CHECKS, ...customPenalties || []];
3939
+ }
3940
+ // ---- 事件记录 ----
3941
+ recordEvent(event) {
3942
+ if (Math.abs(event.delta_value) > this.config.caps.max_single_event) {
3943
+ event.delta_value = event.delta_value > 0 ? this.config.caps.max_single_event : -this.config.caps.max_single_event;
3944
+ }
3945
+ const exists = this.eventStore.find((e) => e.event_id === event.event_id);
3946
+ if (exists) return exists;
3947
+ this.eventStore.push(event);
3948
+ return event;
3949
+ }
3950
+ // ---- 归因 ----
3951
+ attribute(traceId, condition, entityType, entityId) {
3952
+ const rule = this.attributionRules.find((r) => r.condition === condition);
3953
+ if (!rule) return null;
3954
+ const event = {
3955
+ event_id: `attr_${traceId}_${Date.now()}`,
3956
+ trace_id: traceId,
3957
+ decision_id: traceId,
3958
+ tenant_id: "default",
3959
+ entity_type: entityType,
3960
+ entity_id: entityId,
3961
+ dimension: this.inferDimension(condition),
3962
+ delta_value: rule.weight * 10,
3963
+ // 基础分 * 权重
3964
+ delta_confidence: rule.weight,
3965
+ baseline_ref: "current",
3966
+ evidence_bundle_hash: "",
3967
+ created_at: Date.now()
3968
+ };
3969
+ return this.recordEvent(event);
3970
+ }
3971
+ // ---- 窗口结算 ----
3972
+ settle(context) {
3973
+ const windowEvents = this.eventStore.filter(
3974
+ (e) => e.tenant_id === context.tenant_id && e.created_at >= context.window_start && e.created_at <= context.window_end
3975
+ );
3976
+ const entityGroups = /* @__PURE__ */ new Map();
3977
+ for (const e of windowEvents) {
3978
+ const key = `${e.entity_type}:${e.entity_id}`;
3979
+ const group = entityGroups.get(key) || [];
3980
+ group.push(e);
3981
+ entityGroups.set(key, group);
3982
+ }
3983
+ const scores = [];
3984
+ for (const [key, events] of entityGroups) {
3985
+ const [entityType, entityId] = key.split(":");
3986
+ let scoreRisk = 0, scoreCost = 0, scoreHuman = 0, scoreStability = 0;
3987
+ let totalConfidence = 0;
3988
+ for (const e of events) {
3989
+ const val = e.delta_value * e.delta_confidence;
3990
+ switch (e.dimension) {
3991
+ case "RISK":
3992
+ scoreRisk += val;
3993
+ break;
3994
+ case "COST":
3995
+ scoreCost += val;
3996
+ break;
3997
+ case "HUMAN":
3998
+ scoreHuman += val;
3999
+ break;
4000
+ case "STABILITY":
4001
+ scoreStability += val;
4002
+ break;
4003
+ }
4004
+ totalConfidence += e.delta_confidence;
4005
+ }
4006
+ if (!this.config.caps.max_risk_positive_when_risk_up && context.risk_regression) {
4007
+ scoreRisk = Math.min(scoreRisk, 0);
4008
+ scoreCost = Math.min(scoreCost, 0);
4009
+ scoreHuman = Math.min(scoreHuman, 0);
4010
+ scoreStability = Math.min(scoreStability, 0);
4011
+ }
4012
+ let penaltyTotal = 0;
4013
+ for (const check of this.penaltyChecks) {
4014
+ penaltyTotal += check.detect(events, context);
4015
+ }
4016
+ const scoreTotal = this.config.weight_risk * scoreRisk + this.config.weight_cost * scoreCost + this.config.weight_human * scoreHuman + this.config.weight_stability * scoreStability - this.config.weight_penalty * penaltyTotal;
4017
+ const avgConfidence = events.length > 0 ? totalConfidence / events.length : 0;
4018
+ const score = {
4019
+ score_id: `score_${entityType}_${entityId}_${context.window_start}`,
4020
+ window_start: context.window_start,
4021
+ window_end: context.window_end,
4022
+ tenant_id: context.tenant_id,
4023
+ entity_type: entityType,
4024
+ entity_id: entityId,
4025
+ score_risk: Math.round(scoreRisk * 100) / 100,
4026
+ score_cost: Math.round(scoreCost * 100) / 100,
4027
+ score_human: Math.round(scoreHuman * 100) / 100,
4028
+ score_stability: Math.round(scoreStability * 100) / 100,
4029
+ score_total: Math.round(scoreTotal * 100) / 100,
4030
+ penalty_total: Math.round(penaltyTotal * 100) / 100,
4031
+ confidence: Math.round(avgConfidence * 100) / 100,
4032
+ score_config_version: this.config.version,
4033
+ created_at: Date.now()
4034
+ };
4035
+ scores.push(score);
4036
+ this.scoreStore.push(score);
4037
+ }
4038
+ return scores;
4039
+ }
4040
+ // ---- 控制面联动 ----
4041
+ getResourceAllocation(entityType, entityId) {
4042
+ const recentScores = this.scoreStore.filter(
4043
+ (s) => s.entity_type === entityType && s.entity_id === entityId
4044
+ );
4045
+ if (recentScores.length === 0) {
4046
+ return {
4047
+ token_budget_multiplier: 1,
4048
+ concurrency_quota_multiplier: 1,
4049
+ auto_approve_eligible: false,
4050
+ requires_dual_review: false
4051
+ };
4052
+ }
4053
+ const latestScore = recentScores[recentScores.length - 1];
4054
+ const total = latestScore.score_total;
4055
+ return {
4056
+ token_budget_multiplier: total > 50 ? 1.5 : total > 0 ? 1 : 0.5,
4057
+ concurrency_quota_multiplier: total > 50 ? 1.3 : total > 0 ? 1 : 0.7,
4058
+ auto_approve_eligible: total > 80 && latestScore.penalty_total === 0,
4059
+ requires_dual_review: total < -20 || latestScore.penalty_total > 30
4060
+ };
4061
+ }
4062
+ // ---- 审计抽查 ----
4063
+ auditSample(entityType, entityId, sampleSize = 3) {
4064
+ const entityEvents = this.eventStore.filter(
4065
+ (e) => e.entity_type === entityType && e.entity_id === entityId
4066
+ );
4067
+ const shuffled = [...entityEvents].sort(() => Math.random() - 0.5);
4068
+ return shuffled.slice(0, Math.min(sampleSize, shuffled.length));
4069
+ }
4070
+ // ---- 辅助 ----
4071
+ inferDimension(condition) {
4072
+ if (condition.includes("RULE") || condition.includes("BLOCK")) return "RISK";
4073
+ if (condition.includes("COST") || condition.includes("CACHE") || condition.includes("CHEAPER")) return "COST";
4074
+ if (condition.includes("HUMAN") || condition.includes("OVERRIDE")) return "HUMAN";
4075
+ return "STABILITY";
4076
+ }
4077
+ getConfig() {
4078
+ return { ...this.config };
4079
+ }
4080
+ getEventCount() {
4081
+ return this.eventStore.length;
4082
+ }
4083
+ getScoreCount() {
4084
+ return this.scoreStore.length;
4085
+ }
4086
+ };
4087
+
4088
+ // src/overrideDriftAnalyzer.ts
4089
+ var DEFAULT_CONFIG6 = {
4090
+ baseline_window_hours: 168,
4091
+ // 7 天基线
4092
+ analysis_window_hours: 24,
4093
+ // 24 小时分析窗口
4094
+ rate_drift_threshold: 0.3,
4095
+ // override 率偏离 30%
4096
+ concentration_threshold: 0.5,
4097
+ // 单一实体占比超 50%
4098
+ risk_drift_threshold: 0.4,
4099
+ // 高风险 override 占比偏离 40%
4100
+ temporal_drift_threshold: 0.3,
4101
+ // 时间分布偏离 30%
4102
+ composite_alert_threshold: 0.5,
4103
+ // 综合漂移指数超 0.5 告警
4104
+ min_sample_size: 10
4105
+ // 最小样本量
4106
+ };
4107
+ var OverrideDriftAnalyzer = class {
4108
+ config;
4109
+ events = [];
4110
+ baselineWindow = null;
4111
+ alerts = [];
4112
+ constructor(config) {
4113
+ this.config = { ...DEFAULT_CONFIG6, ...config };
4114
+ }
4115
+ // ---- 事件记录 ----
4116
+ recordOverride(event) {
4117
+ if (this.events.find((e) => e.event_id === event.event_id)) return;
4118
+ this.events.push(event);
4119
+ }
4120
+ // ---- 窗口统计 ----
4121
+ computeWindow(start, end, totalDecisions) {
4122
+ const windowEvents = this.events.filter(
4123
+ (e) => e.created_at >= start && e.created_at <= end
4124
+ );
4125
+ const byActor = /* @__PURE__ */ new Map();
4126
+ const byRule = /* @__PURE__ */ new Map();
4127
+ const byRiskLevel = { LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0 };
4128
+ const byHour = new Array(24).fill(0);
4129
+ for (const e of windowEvents) {
4130
+ byActor.set(e.actor_id, (byActor.get(e.actor_id) || 0) + 1);
4131
+ byRule.set(e.rule_id, (byRule.get(e.rule_id) || 0) + 1);
4132
+ byRiskLevel[e.risk_level] = (byRiskLevel[e.risk_level] || 0) + 1;
4133
+ const hour = new Date(e.created_at).getHours();
4134
+ byHour[hour]++;
4135
+ }
4136
+ const total = totalDecisions || Math.max(windowEvents.length * 5, 1);
4137
+ return {
4138
+ window_start: start,
4139
+ window_end: end,
4140
+ total_decisions: total,
4141
+ total_overrides: windowEvents.length,
4142
+ override_rate: total > 0 ? windowEvents.length / total : 0,
4143
+ by_actor: byActor,
4144
+ by_rule: byRule,
4145
+ by_risk_level: byRiskLevel,
4146
+ by_hour: byHour
4147
+ };
4148
+ }
4149
+ // ---- 基线计算 ----
4150
+ updateBaseline(totalDecisions) {
4151
+ const now = Date.now();
4152
+ const start = now - this.config.baseline_window_hours * 60 * 60 * 1e3;
4153
+ this.baselineWindow = this.computeWindow(start, now, totalDecisions);
4154
+ return this.baselineWindow;
4155
+ }
4156
+ // ---- 漂移指数计算 ----
4157
+ calculateDriftIndex(currentWindow, totalDecisions) {
4158
+ const now = Date.now();
4159
+ const current = currentWindow || this.computeWindow(
4160
+ now - this.config.analysis_window_hours * 60 * 60 * 1e3,
4161
+ now,
4162
+ totalDecisions
4163
+ );
4164
+ if (!this.baselineWindow) {
4165
+ this.updateBaseline(totalDecisions);
4166
+ }
4167
+ const baseline = this.baselineWindow;
4168
+ const rateDrift = baseline.override_rate > 0 ? Math.abs(current.override_rate - baseline.override_rate) / baseline.override_rate : current.override_rate > 0 ? 1 : 0;
4169
+ const actorConcentration = this.calculateConcentration(current.by_actor, current.total_overrides);
4170
+ const baselineActorConc = this.calculateConcentration(baseline.by_actor, baseline.total_overrides);
4171
+ const concentrationDrift = Math.abs(actorConcentration - baselineActorConc);
4172
+ const currentHighRisk = ((current.by_risk_level["HIGH"] || 0) + (current.by_risk_level["CRITICAL"] || 0)) / Math.max(current.total_overrides, 1);
4173
+ const baselineHighRisk = ((baseline.by_risk_level["HIGH"] || 0) + (baseline.by_risk_level["CRITICAL"] || 0)) / Math.max(baseline.total_overrides, 1);
4174
+ const riskDrift = Math.abs(currentHighRisk - baselineHighRisk);
4175
+ const temporalDrift = this.calculateTemporalDrift(current.by_hour, baseline.by_hour);
4176
+ const composite = rateDrift * 0.35 + concentrationDrift * 0.25 + riskDrift * 0.25 + temporalDrift * 0.15;
4177
+ const trend = this.determineTrend(composite);
4178
+ return {
4179
+ value: Math.min(Math.round(composite * 1e3) / 1e3, 1),
4180
+ rate_drift: Math.round(rateDrift * 1e3) / 1e3,
4181
+ concentration_drift: Math.round(concentrationDrift * 1e3) / 1e3,
4182
+ risk_drift: Math.round(riskDrift * 1e3) / 1e3,
4183
+ temporal_drift: Math.round(temporalDrift * 1e3) / 1e3,
4184
+ trend
4185
+ };
4186
+ }
4187
+ // ---- 分析 & 告警 ----
4188
+ analyze(totalDecisions) {
4189
+ const driftIndex = this.calculateDriftIndex(void 0, totalDecisions);
4190
+ if (driftIndex.value < this.config.composite_alert_threshold) {
4191
+ return null;
4192
+ }
4193
+ const patterns = this.detectPatterns(driftIndex);
4194
+ const recommendations = this.generateRecommendations(driftIndex, patterns);
4195
+ const severity = driftIndex.value >= 0.8 ? "CRITICAL" : driftIndex.value >= 0.5 ? "WARN" : "INFO";
4196
+ const alert = {
4197
+ alert_id: `da_${Date.now()}`,
4198
+ drift_index: driftIndex,
4199
+ severity,
4200
+ message: `Override drift detected: composite index = ${driftIndex.value} (${driftIndex.trend})`,
4201
+ patterns_detected: patterns,
4202
+ recommendations,
4203
+ created_at: Date.now()
4204
+ };
4205
+ this.alerts.push(alert);
4206
+ return alert;
4207
+ }
4208
+ // ---- 模式检测 ----
4209
+ detectPatterns(driftIndex) {
4210
+ const patterns = [];
4211
+ if (driftIndex.rate_drift > this.config.rate_drift_threshold) {
4212
+ patterns.push({
4213
+ pattern_type: "RATE_SPIKE",
4214
+ description: `Override rate increased by ${(driftIndex.rate_drift * 100).toFixed(1)}% from baseline`,
4215
+ evidence: { rate_drift: driftIndex.rate_drift },
4216
+ confidence: Math.min(driftIndex.rate_drift, 1)
4217
+ });
4218
+ }
4219
+ if (driftIndex.concentration_drift > this.config.concentration_threshold) {
4220
+ patterns.push({
4221
+ pattern_type: "ACTOR_CONCENTRATION",
4222
+ description: "Override activity concentrated on fewer actors than baseline",
4223
+ evidence: { concentration_drift: driftIndex.concentration_drift },
4224
+ confidence: Math.min(driftIndex.concentration_drift, 1)
4225
+ });
4226
+ }
4227
+ if (driftIndex.risk_drift > this.config.risk_drift_threshold) {
4228
+ patterns.push({
4229
+ pattern_type: "RISK_ESCALATION",
4230
+ description: `High-risk override proportion shifted by ${(driftIndex.risk_drift * 100).toFixed(1)}%`,
4231
+ evidence: { risk_drift: driftIndex.risk_drift },
4232
+ confidence: Math.min(driftIndex.risk_drift, 1)
4233
+ });
4234
+ }
4235
+ if (driftIndex.temporal_drift > this.config.temporal_drift_threshold) {
4236
+ patterns.push({
4237
+ pattern_type: "TIME_ANOMALY",
4238
+ description: "Override time distribution deviates from baseline pattern",
4239
+ evidence: { temporal_drift: driftIndex.temporal_drift },
4240
+ confidence: Math.min(driftIndex.temporal_drift, 1)
4241
+ });
4242
+ }
4243
+ return patterns;
4244
+ }
4245
+ // ---- 建议生成 ----
4246
+ generateRecommendations(driftIndex, patterns) {
4247
+ const recs = [];
4248
+ if (patterns.some((p) => p.pattern_type === "RATE_SPIKE")) {
4249
+ recs.push("Review recent policy changes that may have increased false positives");
4250
+ recs.push("Check if new rules are overly restrictive, causing excessive overrides");
4251
+ }
4252
+ if (patterns.some((p) => p.pattern_type === "ACTOR_CONCENTRATION")) {
4253
+ recs.push("Investigate concentrated override activity for potential abuse");
4254
+ recs.push("Consider implementing per-actor override quotas");
4255
+ }
4256
+ if (patterns.some((p) => p.pattern_type === "RISK_ESCALATION")) {
4257
+ recs.push("Audit high-risk overrides for potential security implications");
4258
+ recs.push("Consider requiring dual approval for high-risk overrides");
4259
+ }
4260
+ if (patterns.some((p) => p.pattern_type === "TIME_ANOMALY")) {
4261
+ recs.push("Check for automated override scripts running at unusual hours");
4262
+ recs.push("Review access patterns during off-hours");
4263
+ }
4264
+ if (driftIndex.value >= 0.8) {
4265
+ recs.push("CRITICAL: Consider activating self-constraint engine to restrict override capability");
4266
+ }
4267
+ return recs;
4268
+ }
4269
+ // ---- 辅助计算 ----
4270
+ calculateConcentration(distribution, total) {
4271
+ if (total === 0) return 0;
4272
+ let herfindahl = 0;
4273
+ for (const [, count] of distribution) {
4274
+ const share = count / total;
4275
+ herfindahl += share * share;
4276
+ }
4277
+ return herfindahl;
4278
+ }
4279
+ calculateTemporalDrift(current, baseline) {
4280
+ const currentTotal = current.reduce((a, b) => a + b, 0) || 1;
4281
+ const baselineTotal = baseline.reduce((a, b) => a + b, 0) || 1;
4282
+ let divergence = 0;
4283
+ for (let i = 0; i < 24; i++) {
4284
+ const p = current[i] / currentTotal;
4285
+ const q = baseline[i] / baselineTotal || 1 / 24;
4286
+ if (p > 0) {
4287
+ divergence += p * Math.log(p / q);
4288
+ }
4289
+ }
4290
+ return Math.min(divergence / 2, 1);
4291
+ }
4292
+ determineTrend(composite) {
4293
+ const recentAlerts = this.alerts.slice(-5);
4294
+ if (recentAlerts.length < 2) return "STABLE";
4295
+ const values = recentAlerts.map((a) => a.drift_index.value);
4296
+ const diffs = values.slice(1).map((v, i) => v - values[i]);
4297
+ const avgDiff = diffs.reduce((a, b) => a + b, 0) / diffs.length;
4298
+ const variance = diffs.reduce((a, b) => a + (b - avgDiff) ** 2, 0) / diffs.length;
4299
+ if (variance > 0.1) return "VOLATILE";
4300
+ if (avgDiff > 0.05) return "RISING";
4301
+ if (avgDiff < -0.05) return "FALLING";
4302
+ return "STABLE";
4303
+ }
4304
+ // ---- 查询 ----
4305
+ getAlerts(limit = 20) {
4306
+ return this.alerts.slice(-limit);
4307
+ }
4308
+ getEventCount() {
4309
+ return this.events.length;
4310
+ }
4311
+ getLatestDriftIndex(totalDecisions) {
4312
+ return this.calculateDriftIndex(void 0, totalDecisions);
4313
+ }
4314
+ getStats() {
4315
+ const now = Date.now();
4316
+ const currentWindow = this.computeWindow(
4317
+ now - this.config.analysis_window_hours * 60 * 60 * 1e3,
4318
+ now
4319
+ );
4320
+ return {
4321
+ total_events: this.events.length,
4322
+ total_alerts: this.alerts.length,
4323
+ baseline_override_rate: this.baselineWindow?.override_rate || 0,
4324
+ current_override_rate: currentWindow.override_rate
4325
+ };
4326
+ }
4327
+ };
4328
+
2057
4329
  // src/index.ts
2058
4330
  var DEFAULT_RULES = [
2059
4331
  // --- HTTP Proxy: Dangerous outbound calls ---
@@ -2545,16 +4817,30 @@ var index_default = PolicyEngine;
2545
4817
  0 && (module.exports = {
2546
4818
  AdaptiveThresholdManager,
2547
4819
  AutoHardenEngine,
4820
+ ContextAccelerator,
4821
+ ContributionSettlementEngine,
2548
4822
  CostGateEnhancedEngine,
4823
+ DEFAULT_CA_CONFIG,
4824
+ DEFAULT_GE_CONFIG,
4825
+ DEFAULT_HARD_RULES,
2549
4826
  DEFAULT_RULES,
4827
+ DEFAULT_SCORING_WEIGHTS,
4828
+ DEFAULT_TSA_CONFIG,
2550
4829
  EvolutionChannelEngine,
2551
4830
  FeatureSwitchesManager,
4831
+ GovernanceEnhancer,
2552
4832
  MultiLevelBudgetEngine,
4833
+ OverrideDriftAnalyzer,
2553
4834
  PolicyEngine,
2554
4835
  PricingRulesEngine,
2555
4836
  RecalculationEngine,
2556
4837
  SOVR_FEATURE_SWITCHES,
4838
+ SelfConstraintEngine,
2557
4839
  SemanticDriftDetectorEngine,
4840
+ TimeSeriesAggregator,
4841
+ TrendAlertEngine,
4842
+ TwoPhaseRouter,
4843
+ ValuationModel,
2558
4844
  compileFromJSON,
2559
4845
  compileRuleSet,
2560
4846
  createAutoHardenEngine,