Files
proffesor-for-testing__agen…/tests/integration/consensus-integration.test.ts
Profa 2253d05618 feat: flatten project structure — archive v2, promote v3 to root
Remove the nested v3/ subdirectory by moving all active source code,
tests, configs, and assets directly to the project root. Archive v2/
(dead code, 847MB) to v2-archive.tar.gz.

Key changes:
- Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/
- Move v3/tsconfig.json, v3/vitest.config.ts to root
- Merge v3/package.json into root package.json (ESM, scripts, deps, exports)
- Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/
- Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes
- Fix all init installer path resolution (3-level-up → 2-level-up)
- Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe"
- Update settings.json ADR/DDD directories to docs/implementation/
- Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks)
- Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces
- Update 15 guidance shards: v3/src/ → src/ path references
- Fix sync interfaces: remove v3/ and v2/ path references
- Fix test path calculations (process.cwd() + '..' no longer needed)
- Fix flaky perf test threshold (500ms → 1000ms for CI environments)
- Fix complexity-analyzer test to match ADR-051 keyword-based eligibility

Build passes, 17,901 tests pass, CLI and MCP bundles verified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:35:41 +00:00

310 lines
9.8 KiB
TypeScript

/**
* Agentic QE v3 - Consensus Engine Integration Test
* Tests the full consensus verification pipeline
*/
import { describe, it, expect, beforeEach } from 'vitest';
import {
createTestConsensusEngine,
createMockProvider,
type SecurityFinding,
type ConsensusEngine,
} from '../../src/coordination/consensus';
// ============================================================================
// Test Helpers
// ============================================================================
/**
* Create a test security finding
*/
function createTestFinding(): SecurityFinding {
return {
id: 'integration-test-finding',
type: 'sql-injection',
category: 'injection',
severity: 'critical',
description: 'SQL injection vulnerability in user input',
explanation: 'Direct string concatenation in SQL query without sanitization',
location: {
file: 'src/api/users.ts',
line: 45,
column: 12,
function: 'getUserById',
},
evidence: [
{
type: 'code-snippet',
content: 'db.query(`SELECT * FROM users WHERE id = ${req.params.id}`)',
confidence: 0.95,
},
{
type: 'data-flow',
content: 'Tainted data flows from req.params.id to SQL query',
confidence: 0.9,
},
],
cweId: 'CWE-89',
owaspCategory: 'A03:2021 - Injection',
remediation: 'Use parameterized queries: db.query("SELECT * FROM users WHERE id = ?", [req.params.id])',
detectedAt: new Date(),
detectedBy: 'integration-test',
};
}
// ============================================================================
// Integration Tests
// ============================================================================
describe('Consensus Engine Integration', () => {
let engine: ConsensusEngine;
beforeEach(() => {
// Create engine with three mock providers
const providers = [
createMockProvider({
id: 'claude',
name: 'Claude',
defaultAssessment: 'confirmed',
defaultConfidence: 0.92,
latencyMs: 150,
}),
createMockProvider({
id: 'gpt',
name: 'GPT-4',
defaultAssessment: 'confirmed',
defaultConfidence: 0.88,
latencyMs: 200,
}),
createMockProvider({
id: 'gemini',
name: 'Gemini',
defaultAssessment: 'confirmed',
defaultConfidence: 0.85,
latencyMs: 180,
}),
];
engine = createTestConsensusEngine(providers, {
minModels: 2,
maxModels: 3,
verifySeverities: ['critical', 'high'],
defaultThreshold: 2 / 3,
enableCostTracking: true,
humanReviewThreshold: 0.7,
});
});
describe('end-to-end verification', () => {
it('should verify a security finding through the full pipeline', async () => {
const finding = createTestFinding();
const result = await engine.verify(finding);
// Verify success
expect(result.success).toBe(true);
if (!result.success) return;
const { value: consensusResult } = result;
// Verify basic properties
expect(consensusResult.finding.id).toBe(finding.id);
expect(consensusResult.votes).toHaveLength(3);
// All models should agree (confirmed)
expect(consensusResult.verdict).toBe('verified');
expect(consensusResult.agreementRatio).toBe(1.0);
// Confidence should be high
expect(consensusResult.confidence).toBeGreaterThan(0.8);
// Should have reasoning
expect(consensusResult.reasoning).toBeDefined();
expect(consensusResult.reasoning.length).toBeGreaterThan(0);
// Should not require human review (high confidence, unanimous)
expect(consensusResult.requiresHumanReview).toBe(false);
// Verify vote details
consensusResult.votes.forEach(vote => {
expect(vote.modelId).toBeDefined();
expect(vote.agrees).toBe(true);
expect(vote.assessment).toBe('confirmed');
expect(vote.confidence).toBeGreaterThan(0.8);
expect(vote.reasoning).toBeDefined();
expect(vote.executionTime).toBeGreaterThan(0);
expect(vote.votedAt).toBeInstanceOf(Date);
});
// Verify cost tracking
expect(consensusResult.totalCost).toBeDefined();
expect(consensusResult.totalCost).toBeGreaterThan(0);
// Verify execution time
expect(consensusResult.totalExecutionTime).toBeGreaterThan(0);
expect(consensusResult.completedAt).toBeInstanceOf(Date);
});
it('should handle batch verification', async () => {
const findings = [
createTestFinding(),
{ ...createTestFinding(), id: 'finding-2' },
{ ...createTestFinding(), id: 'finding-3' },
];
const result = await engine.verifyBatch(findings);
expect(result.success).toBe(true);
if (!result.success) return;
expect(result.value).toHaveLength(3);
result.value.forEach((consensusResult, index) => {
expect(consensusResult.finding.id).toBe(findings[index].id);
expect(consensusResult.verdict).toBe('verified');
expect(consensusResult.votes).toHaveLength(3);
});
});
it('should track statistics across multiple verifications', async () => {
const finding1 = createTestFinding();
const finding2 = { ...createTestFinding(), id: 'finding-2' };
// Initial stats
let stats = engine.getStats();
expect(stats.totalVerifications).toBe(0);
// First verification
await engine.verify(finding1);
stats = engine.getStats();
expect(stats.totalVerifications).toBe(1);
expect(stats.byVerdict.verified).toBe(1);
// Second verification
await engine.verify(finding2);
stats = engine.getStats();
expect(stats.totalVerifications).toBe(2);
expect(stats.byVerdict.verified).toBe(2);
// Model stats should be tracked
expect(stats.modelStats.claude).toBeDefined();
expect(stats.modelStats.claude.votes).toBe(2);
expect(stats.modelStats.claude.agreements).toBe(2);
expect(stats.modelStats.claude.averageConfidence).toBeGreaterThan(0.8);
// Average metrics
expect(stats.averageConfidence).toBeGreaterThan(0.8);
expect(stats.averageExecutionTime).toBeGreaterThan(0);
expect(stats.totalCost).toBeGreaterThan(0);
});
});
describe('disputed findings', () => {
it('should handle findings where models disagree', async () => {
// Create engine with mixed assessments
const providers = [
createMockProvider({
id: 'agree-1',
name: 'Agrees 1',
defaultAssessment: 'confirmed',
defaultConfidence: 0.9,
}),
createMockProvider({
id: 'disagree-1',
name: 'Disagrees 1',
defaultAssessment: 'rejected',
defaultConfidence: 0.85,
}),
createMockProvider({
id: 'agree-2',
name: 'Agrees 2',
defaultAssessment: 'confirmed',
defaultConfidence: 0.88,
}),
];
const disputedEngine = createTestConsensusEngine(providers, {
minModels: 2,
maxModels: 3,
verifySeverities: ['critical'],
defaultThreshold: 2 / 3,
humanReviewThreshold: 0.7,
});
const finding = createTestFinding();
const result = await disputedEngine.verify(finding);
expect(result.success).toBe(true);
if (!result.success) return;
const { value: consensusResult } = result;
// Should still reach majority verdict (2/3 agree)
expect(consensusResult.verdict).toBe('verified');
expect(consensusResult.agreementRatio).toBeCloseTo(2 / 3);
// Should have votes from all models
expect(consensusResult.votes).toHaveLength(3);
// Reasoning should mention both perspectives
expect(consensusResult.reasoning).toContain('agree');
expect(consensusResult.reasoning).toContain('disagree');
});
});
describe('error handling', () => {
it('should handle provider failures gracefully', async () => {
const providers = [
createMockProvider({
id: 'working-1',
name: 'Working 1',
defaultAssessment: 'confirmed',
defaultConfidence: 0.9,
}),
createMockProvider({
id: 'failing',
name: 'Failing Provider',
failureRate: 1.0, // Always fail
}),
createMockProvider({
id: 'working-2',
name: 'Working 2',
defaultAssessment: 'confirmed',
defaultConfidence: 0.88,
}),
];
const resilientEngine = createTestConsensusEngine(providers, {
minModels: 2,
maxModels: 3,
verifySeverities: ['critical'],
defaultThreshold: 0.5,
});
const finding = createTestFinding();
const result = await resilientEngine.verify(finding);
expect(result.success).toBe(true);
if (!result.success) return;
const { value: consensusResult } = result;
// Should still reach verdict with 2 working providers
expect(consensusResult.votes).toHaveLength(3);
// One vote should have an error
const errorVotes = consensusResult.votes.filter(v => v.error);
expect(errorVotes).toHaveLength(1);
// Should still be able to reach consensus with remaining votes
expect(consensusResult.verdict).toBe('verified');
// Statistics should track errors
const stats = resilientEngine.getStats();
const failingStats = stats.modelStats.failing;
expect(failingStats).toBeDefined();
expect(failingStats.errors).toBe(1);
});
});
});