mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
eebb76731e
Milestone 3 — Scale & Optimization (R7-R10): - R7: Meta-learning enhancements (DecayingBeta, PlateauDetector with CUSUM, ParetoFront, CuriosityBonus) wired into DomainTransferEngine - R8: PageRank pattern importance solver with citation graph pipeline (PatternCitationGraph bootstraps from 129 existing patterns, blended scoring in pattern-promotion.ts) - R9: Spectral graph sparsifier (degree-based leverage heuristic) wired into mincut-wrapper.ts as optional preprocessing - R10: Reservoir replay buffer with coherence-gated admission and CUSUM drift detection, wired into ExperienceReplay (write + read paths) Milestone 4 — Advanced Learning (R11-R12): - R11: E-prop online learning (12 bytes/synapse, eligibility traces, feedback alignment) — RL algorithm #10, extends BaseRLAlgorithm - R12: Granger causality for test failure prediction (VAR + F-test with full statistical math) wired into defect-intelligence coordinator with persistent history accumulation Infrastructure: - 8 feature flags (all default true per opt-out policy), convenience functions, env var support, CLI descriptions - RLAlgorithmType union: 9 → 10 members (added 'eprop') - ADR-087 status: Proposed → Active (M1-4 complete) - 234 new tests across 8 test files, all passing - Performance benchmarks for PageRank, sparsification, reservoir admission - 0 regressions in existing test suite Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
166 lines
6.3 KiB
TypeScript
166 lines
6.3 KiB
TypeScript
/**
|
|
* Milestone 3 Performance Benchmarks (ADR-087)
|
|
*
|
|
* Measures PageRank solver scaling, spectral sparsification throughput,
|
|
* and reservoir admission latency at increasing scales.
|
|
*
|
|
* Run: npx vitest run tests/performance/milestone3-benchmarks.test.ts
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
PageRankSolver,
|
|
type PatternGraph,
|
|
} from '../../src/integrations/ruvector/solver-adapter';
|
|
import { SpectralSparsifier } from '../../src/integrations/ruvector/spectral-sparsifier';
|
|
import { ReservoirReplayBuffer } from '../../src/integrations/ruvector/reservoir-replay';
|
|
|
|
// ============================================================================
|
|
// Helpers
|
|
// ============================================================================
|
|
|
|
/** Build a cycle graph with random cross-edges for realistic structure */
|
|
function buildScaleGraph(nodeCount: number, edgesPerNode: number): PatternGraph {
|
|
const nodes: string[] = [];
|
|
const edges: Array<[number, number, number]> = [];
|
|
for (let i = 0; i < nodeCount; i++) {
|
|
nodes.push(`p-${i}`);
|
|
// Cycle edge
|
|
edges.push([i, (i + 1) % nodeCount, 1]);
|
|
// Random cross-edges
|
|
for (let j = 1; j < edgesPerNode; j++) {
|
|
const target = (i + j * 7 + 3) % nodeCount; // deterministic pseudo-random
|
|
if (target !== i) edges.push([i, target, 0.5 + (j % 3) * 0.25]);
|
|
}
|
|
}
|
|
return { nodes, edges };
|
|
}
|
|
|
|
// ============================================================================
|
|
// R8: PageRank Solver Scaling
|
|
// ============================================================================
|
|
|
|
describe('R8: PageRank solver scaling benchmarks', () => {
|
|
const solver = new PageRankSolver();
|
|
|
|
it('100 nodes — should complete in < 10ms', () => {
|
|
const graph = buildScaleGraph(100, 3);
|
|
const start = performance.now();
|
|
const scores = solver.computeImportance(graph);
|
|
const elapsed = performance.now() - start;
|
|
|
|
expect(scores.size).toBe(100);
|
|
expect(elapsed).toBeLessThan(10);
|
|
console.log(` PageRank 100 nodes (${graph.edges.length} edges): ${elapsed.toFixed(2)}ms`);
|
|
});
|
|
|
|
it('1K nodes — should complete in < 100ms', () => {
|
|
const graph = buildScaleGraph(1000, 5);
|
|
const start = performance.now();
|
|
const scores = solver.computeImportance(graph);
|
|
const elapsed = performance.now() - start;
|
|
|
|
expect(scores.size).toBe(1000);
|
|
expect(elapsed).toBeLessThan(100);
|
|
console.log(` PageRank 1K nodes (${graph.edges.length} edges): ${elapsed.toFixed(2)}ms`);
|
|
});
|
|
|
|
it('5K nodes — should complete in < 2s', () => {
|
|
const graph = buildScaleGraph(5000, 5);
|
|
const start = performance.now();
|
|
const scores = solver.computeImportance(graph);
|
|
const elapsed = performance.now() - start;
|
|
|
|
expect(scores.size).toBe(5000);
|
|
expect(elapsed).toBeLessThan(2000);
|
|
console.log(` PageRank 5K nodes (${graph.edges.length} edges): ${elapsed.toFixed(2)}ms`);
|
|
});
|
|
|
|
it('scaling should be roughly linear (not quadratic)', () => {
|
|
// Measure 500 vs 2000 nodes — ratio should be < 8x (linear would be 4x)
|
|
const small = buildScaleGraph(500, 4);
|
|
const large = buildScaleGraph(2000, 4);
|
|
|
|
const startSmall = performance.now();
|
|
solver.computeImportance(small);
|
|
const elapsedSmall = performance.now() - startSmall;
|
|
|
|
const startLarge = performance.now();
|
|
solver.computeImportance(large);
|
|
const elapsedLarge = performance.now() - startLarge;
|
|
|
|
const ratio = elapsedLarge / Math.max(elapsedSmall, 0.01);
|
|
console.log(` Scaling ratio (4x nodes): ${ratio.toFixed(1)}x (linear=4x, quadratic=16x)`);
|
|
// Should be sub-quadratic — allow up to 16x for overhead + CI variance
|
|
// (linear=4x, quadratic=16x; anything under 16x confirms sub-quadratic)
|
|
expect(ratio).toBeLessThan(16);
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// R9: Spectral Sparsification Throughput
|
|
// ============================================================================
|
|
|
|
describe('R9: Spectral sparsifier benchmarks', () => {
|
|
it('500 edges — should sparsify in < 50ms', () => {
|
|
const n = 32; // K32 has 496 edges
|
|
const edges: Array<[number, number, number]> = [];
|
|
for (let i = 0; i < n; i++) {
|
|
for (let j = i + 1; j < n; j++) {
|
|
edges.push([i, j, 1]);
|
|
}
|
|
}
|
|
|
|
const sparsifier = new SpectralSparsifier({ epsilon: 0.3, seed: 42 });
|
|
const start = performance.now();
|
|
const result = sparsifier.sparsify({ nodeCount: n, edges });
|
|
const elapsed = performance.now() - start;
|
|
|
|
expect(result.edges.length).toBeLessThan(edges.length);
|
|
expect(elapsed).toBeLessThan(50);
|
|
console.log(` Sparsify ${edges.length} edges → ${result.edges.length}: ${elapsed.toFixed(2)}ms`);
|
|
});
|
|
|
|
it('1K edges — should sparsify in < 200ms', () => {
|
|
const n = 46; // K46 has 1035 edges
|
|
const edges: Array<[number, number, number]> = [];
|
|
for (let i = 0; i < n; i++) {
|
|
for (let j = i + 1; j < n; j++) {
|
|
edges.push([i, j, 1]);
|
|
}
|
|
}
|
|
|
|
const sparsifier = new SpectralSparsifier({ epsilon: 0.3, seed: 42 });
|
|
const start = performance.now();
|
|
const result = sparsifier.sparsify({ nodeCount: n, edges });
|
|
const elapsed = performance.now() - start;
|
|
|
|
expect(result.edges.length).toBeLessThan(edges.length);
|
|
expect(elapsed).toBeLessThan(200);
|
|
console.log(` Sparsify ${edges.length} edges → ${result.edges.length}: ${elapsed.toFixed(2)}ms`);
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// R10: Reservoir Admission Throughput
|
|
// ============================================================================
|
|
|
|
describe('R10: Reservoir admission benchmark', () => {
|
|
it('10K admissions should complete in < 100ms (< 0.01ms each)', () => {
|
|
const buffer = new ReservoirReplayBuffer<string>({ capacity: 1000 });
|
|
|
|
const start = performance.now();
|
|
for (let i = 0; i < 10000; i++) {
|
|
buffer.admit(`exp-${i}`, `data-${i}`, 0.3 + Math.random() * 0.7);
|
|
}
|
|
const elapsed = performance.now() - start;
|
|
|
|
expect(buffer.size()).toBe(1000); // capped at capacity
|
|
expect(elapsed).toBeLessThan(100);
|
|
const perAdmission = elapsed / 10000;
|
|
console.log(` 10K admissions: ${elapsed.toFixed(2)}ms (${perAdmission.toFixed(4)}ms/admission)`);
|
|
// Plan requires < 0.1ms per admission
|
|
expect(perAdmission).toBeLessThan(0.1);
|
|
});
|
|
});
|