mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2253d05618
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>
754 lines
26 KiB
TypeScript
754 lines
26 KiB
TypeScript
/**
|
|
* ADR-052 Action A4.5: Final Quality Gates Verification
|
|
*
|
|
* This test file validates the quality gates for the coherence module:
|
|
* 1. All 6 engine adapters are functional
|
|
* 2. CoherenceService initializes successfully
|
|
* 3. MCP tools are registered (4 tools: check, audit, consensus, collapse)
|
|
* 4. False negative rate: Known contradictions must be detected (100%)
|
|
* 5. False positive rate: Coherent inputs must not be falsely flagged (<5%)
|
|
*
|
|
* @module tests/integration/coherence-quality-gates.test
|
|
*/
|
|
|
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
|
|
// Import coherence service and types
|
|
import {
|
|
CoherenceService,
|
|
createCoherenceService,
|
|
type CoherenceNode,
|
|
type IWasmLoader,
|
|
type WasmModule,
|
|
type CoherenceLogger,
|
|
DEFAULT_COHERENCE_LOGGER,
|
|
} from '../../src/integrations/coherence/index';
|
|
|
|
// Import engine adapters
|
|
import { CohomologyAdapter } from '../../src/integrations/coherence/engines/cohomology-adapter';
|
|
import { SpectralAdapter } from '../../src/integrations/coherence/engines/spectral-adapter';
|
|
import { CausalAdapter } from '../../src/integrations/coherence/engines/causal-adapter';
|
|
import { CategoryAdapter } from '../../src/integrations/coherence/engines/category-adapter';
|
|
import { HomotopyAdapter } from '../../src/integrations/coherence/engines/homotopy-adapter';
|
|
import { WitnessAdapter } from '../../src/integrations/coherence/engines/witness-adapter';
|
|
|
|
// Import MCP tool registry
|
|
import {
|
|
QE_TOOLS,
|
|
QE_TOOL_NAMES,
|
|
} from '../../src/mcp/tools/registry';
|
|
|
|
// Import coherence tool names directly from coherence module
|
|
import { COHERENCE_TOOL_NAMES } from '../../src/mcp/tools/coherence/index';
|
|
|
|
// ============================================================================
|
|
// Mock WASM Loader for Testing
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Creates a mock WASM loader with fallback behavior enabled
|
|
*/
|
|
function createMockWasmLoader(): IWasmLoader {
|
|
return {
|
|
async isAvailable(): Promise<boolean> {
|
|
// Return false to trigger fallback mode (TypeScript implementation)
|
|
return false;
|
|
},
|
|
async load(): Promise<WasmModule> {
|
|
throw new Error('WASM not available - using fallback');
|
|
},
|
|
getModule(): WasmModule {
|
|
throw new Error('WASM not available - using fallback');
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a mock WASM loader that simulates WASM being available
|
|
* with mock engine implementations for testing
|
|
*/
|
|
function createMockWasmLoaderWithEngines(): IWasmLoader {
|
|
// Mock engine implementations
|
|
const mockCohomologyEngine = {
|
|
computeCohomology: () => ({ dimension: 1, generators: [] }),
|
|
computeGlobalSections: () => ({ sections: [] }),
|
|
consistencyEnergy: () => 0.1,
|
|
detectObstructions: () => [],
|
|
free: () => {},
|
|
};
|
|
|
|
const mockSpectralEngine = {
|
|
algebraicConnectivity: () => 0.5,
|
|
computeCheegerBounds: () => ({ lower: 0.1, upper: 0.9 }),
|
|
computeEigenvalues: () => [1.0, 0.5, 0.3],
|
|
computeFiedlerVector: () => [0.1, -0.2, 0.3],
|
|
computeSpectralGap: () => 0.5,
|
|
predictMinCut: () => ({ cost: 2, partition: [] }),
|
|
free: () => {},
|
|
};
|
|
|
|
const mockCausalEngine = {
|
|
checkDSeparation: () => ({ isSeparated: true }),
|
|
computeCausalEffect: () => ({ effect: 0.3 }),
|
|
findConfounders: () => [],
|
|
isValidDag: () => true,
|
|
topologicalOrder: () => [],
|
|
free: () => {},
|
|
};
|
|
|
|
const mockCategoryEngine = {
|
|
applyMorphism: () => ({}),
|
|
composeMorphisms: () => ({}),
|
|
functorialRetrieve: () => [],
|
|
verifyCategoryLaws: () => true,
|
|
verifyFunctoriality: () => true,
|
|
free: () => {},
|
|
};
|
|
|
|
const mockHoTTEngine = {
|
|
checkTypeEquivalence: () => true,
|
|
composePaths: () => ({}),
|
|
createReflPath: () => ({}),
|
|
inferType: () => ({ type: 'any' }),
|
|
invertPath: () => ({}),
|
|
typeCheck: () => ({ isValid: true }),
|
|
free: () => {},
|
|
};
|
|
|
|
const mockQuantumEngine = {
|
|
applyGate: () => ({}),
|
|
computeEntanglementEntropy: () => 0.5,
|
|
computeFidelity: () => ({ fidelity: 0.99 }),
|
|
computeTopologicalInvariants: () => ({ euler: 1 }),
|
|
createGHZState: () => ({}),
|
|
createWState: () => ({}),
|
|
free: () => {},
|
|
};
|
|
|
|
const mockModule: WasmModule = {
|
|
CohomologyEngine: class {
|
|
computeCohomology = mockCohomologyEngine.computeCohomology;
|
|
computeGlobalSections = mockCohomologyEngine.computeGlobalSections;
|
|
consistencyEnergy = mockCohomologyEngine.consistencyEnergy;
|
|
detectObstructions = mockCohomologyEngine.detectObstructions;
|
|
free = mockCohomologyEngine.free;
|
|
} as unknown as WasmModule['CohomologyEngine'],
|
|
SpectralEngine: Object.assign(
|
|
class {
|
|
algebraicConnectivity = mockSpectralEngine.algebraicConnectivity;
|
|
computeCheegerBounds = mockSpectralEngine.computeCheegerBounds;
|
|
computeEigenvalues = mockSpectralEngine.computeEigenvalues;
|
|
computeFiedlerVector = mockSpectralEngine.computeFiedlerVector;
|
|
computeSpectralGap = mockSpectralEngine.computeSpectralGap;
|
|
predictMinCut = mockSpectralEngine.predictMinCut;
|
|
free = mockSpectralEngine.free;
|
|
},
|
|
{
|
|
withConfig: () => mockSpectralEngine,
|
|
}
|
|
) as unknown as WasmModule['SpectralEngine'],
|
|
CausalEngine: class {
|
|
checkDSeparation = mockCausalEngine.checkDSeparation;
|
|
computeCausalEffect = mockCausalEngine.computeCausalEffect;
|
|
findConfounders = mockCausalEngine.findConfounders;
|
|
isValidDag = mockCausalEngine.isValidDag;
|
|
topologicalOrder = mockCausalEngine.topologicalOrder;
|
|
free = mockCausalEngine.free;
|
|
} as unknown as WasmModule['CausalEngine'],
|
|
CategoryEngine: class {
|
|
applyMorphism = mockCategoryEngine.applyMorphism;
|
|
composeMorphisms = mockCategoryEngine.composeMorphisms;
|
|
functorialRetrieve = mockCategoryEngine.functorialRetrieve;
|
|
verifyCategoryLaws = mockCategoryEngine.verifyCategoryLaws;
|
|
verifyFunctoriality = mockCategoryEngine.verifyFunctoriality;
|
|
free = mockCategoryEngine.free;
|
|
} as unknown as WasmModule['CategoryEngine'],
|
|
HoTTEngine: Object.assign(
|
|
class {
|
|
checkTypeEquivalence = mockHoTTEngine.checkTypeEquivalence;
|
|
composePaths = mockHoTTEngine.composePaths;
|
|
createReflPath = mockHoTTEngine.createReflPath;
|
|
inferType = mockHoTTEngine.inferType;
|
|
invertPath = mockHoTTEngine.invertPath;
|
|
typeCheck = mockHoTTEngine.typeCheck;
|
|
free = mockHoTTEngine.free;
|
|
},
|
|
{
|
|
withStrictMode: () => mockHoTTEngine,
|
|
}
|
|
) as unknown as WasmModule['HoTTEngine'],
|
|
QuantumEngine: class {
|
|
applyGate = mockQuantumEngine.applyGate;
|
|
computeEntanglementEntropy = mockQuantumEngine.computeEntanglementEntropy;
|
|
computeFidelity = mockQuantumEngine.computeFidelity;
|
|
computeTopologicalInvariants = mockQuantumEngine.computeTopologicalInvariants;
|
|
createGHZState = mockQuantumEngine.createGHZState;
|
|
createWState = mockQuantumEngine.createWState;
|
|
free = mockQuantumEngine.free;
|
|
} as unknown as WasmModule['QuantumEngine'],
|
|
getVersion: () => '1.0.0-mock',
|
|
initModule: () => {},
|
|
};
|
|
|
|
let loaded = false;
|
|
|
|
return {
|
|
async isAvailable(): Promise<boolean> {
|
|
return true;
|
|
},
|
|
async load(): Promise<WasmModule> {
|
|
loaded = true;
|
|
return mockModule;
|
|
},
|
|
getModule(): WasmModule {
|
|
if (!loaded) throw new Error('Module not loaded');
|
|
return mockModule;
|
|
},
|
|
};
|
|
}
|
|
|
|
// ============================================================================
|
|
// Helper Functions
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Generate a random embedding vector
|
|
*/
|
|
function generateRandomEmbedding(dimension: number = 128, seed?: number): number[] {
|
|
const embedding: number[] = [];
|
|
let randomVal = seed || Math.random() * 1000;
|
|
|
|
for (let i = 0; i < dimension; i++) {
|
|
// Simple deterministic random if seed provided
|
|
randomVal = (randomVal * 9301 + 49297) % 233280;
|
|
embedding.push((randomVal / 233280 - 0.5) * 2);
|
|
}
|
|
|
|
// Normalize
|
|
const magnitude = Math.sqrt(embedding.reduce((sum, v) => sum + v * v, 0));
|
|
return embedding.map((v) => v / magnitude);
|
|
}
|
|
|
|
/**
|
|
* Generate coherent embeddings (similar vectors)
|
|
*/
|
|
function generateCoherentEmbeddings(count: number, dimension: number = 128): number[][] {
|
|
// Generate a base vector
|
|
const base = generateRandomEmbedding(dimension, 42);
|
|
const embeddings: number[][] = [base];
|
|
|
|
// Generate similar vectors by adding small noise
|
|
for (let i = 1; i < count; i++) {
|
|
const noise = generateRandomEmbedding(dimension, 100 + i);
|
|
const embedding = base.map((v, idx) => v + noise[idx] * 0.1); // 10% noise
|
|
|
|
// Normalize
|
|
const magnitude = Math.sqrt(embedding.reduce((sum, v) => sum + v * v, 0));
|
|
embeddings.push(embedding.map((v) => v / magnitude));
|
|
}
|
|
|
|
return embeddings;
|
|
}
|
|
|
|
/**
|
|
* Generate contradictory embeddings (opposite vectors)
|
|
*/
|
|
function generateContradictoryEmbeddings(dimension: number = 128): [number[], number[]] {
|
|
const embedding1 = generateRandomEmbedding(dimension, 42);
|
|
// Create opposite vector (negated)
|
|
const embedding2 = embedding1.map((v) => -v);
|
|
|
|
return [embedding1, embedding2];
|
|
}
|
|
|
|
// ============================================================================
|
|
// Quality Gates Tests
|
|
// ============================================================================
|
|
|
|
describe('ADR-052 Quality Gates', () => {
|
|
describe('Engine Adapter Functionality', () => {
|
|
const mockLoader = createMockWasmLoaderWithEngines();
|
|
|
|
it('should verify CohomologyAdapter can be instantiated', () => {
|
|
const adapter = new CohomologyAdapter(mockLoader, DEFAULT_COHERENCE_LOGGER);
|
|
expect(adapter).toBeDefined();
|
|
expect(adapter.isInitialized()).toBe(false);
|
|
});
|
|
|
|
it('should verify SpectralAdapter can be instantiated', () => {
|
|
const adapter = new SpectralAdapter(mockLoader, DEFAULT_COHERENCE_LOGGER);
|
|
expect(adapter).toBeDefined();
|
|
expect(adapter.isInitialized()).toBe(false);
|
|
});
|
|
|
|
it('should verify CausalAdapter can be instantiated', () => {
|
|
const adapter = new CausalAdapter(mockLoader, DEFAULT_COHERENCE_LOGGER);
|
|
expect(adapter).toBeDefined();
|
|
expect(adapter.isInitialized()).toBe(false);
|
|
});
|
|
|
|
it('should verify CategoryAdapter can be instantiated', () => {
|
|
const adapter = new CategoryAdapter(mockLoader, DEFAULT_COHERENCE_LOGGER);
|
|
expect(adapter).toBeDefined();
|
|
expect(adapter.isInitialized()).toBe(false);
|
|
});
|
|
|
|
it('should verify HomotopyAdapter can be instantiated', () => {
|
|
const adapter = new HomotopyAdapter(mockLoader, DEFAULT_COHERENCE_LOGGER);
|
|
expect(adapter).toBeDefined();
|
|
expect(adapter.isInitialized()).toBe(false);
|
|
});
|
|
|
|
it('should verify WitnessAdapter can be instantiated', () => {
|
|
const adapter = new WitnessAdapter(mockLoader, DEFAULT_COHERENCE_LOGGER);
|
|
expect(adapter).toBeDefined();
|
|
expect(adapter.isInitialized()).toBe(false);
|
|
});
|
|
|
|
it('should have all 6 engine adapters available', () => {
|
|
const adapters = [
|
|
CohomologyAdapter,
|
|
SpectralAdapter,
|
|
CausalAdapter,
|
|
CategoryAdapter,
|
|
HomotopyAdapter,
|
|
WitnessAdapter,
|
|
];
|
|
|
|
expect(adapters).toHaveLength(6);
|
|
adapters.forEach((Adapter) => {
|
|
expect(Adapter).toBeDefined();
|
|
expect(typeof Adapter).toBe('function');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('CoherenceService Initialization', () => {
|
|
it('should initialize successfully with fallback enabled', async () => {
|
|
const mockLoader = createMockWasmLoader();
|
|
const service = await createCoherenceService(mockLoader, {
|
|
fallbackEnabled: true,
|
|
});
|
|
|
|
expect(service).toBeDefined();
|
|
expect(service.isInitialized()).toBe(true);
|
|
|
|
await service.dispose();
|
|
});
|
|
|
|
it('should initialize with mock WASM engines', async () => {
|
|
const mockLoader = createMockWasmLoaderWithEngines();
|
|
const service = await createCoherenceService(mockLoader, {
|
|
fallbackEnabled: true,
|
|
});
|
|
|
|
expect(service).toBeDefined();
|
|
expect(service.isInitialized()).toBe(true);
|
|
|
|
await service.dispose();
|
|
});
|
|
|
|
it('should track statistics after initialization', async () => {
|
|
const mockLoader = createMockWasmLoader();
|
|
const service = await createCoherenceService(mockLoader, {
|
|
fallbackEnabled: true,
|
|
});
|
|
|
|
const stats = service.getStats();
|
|
expect(stats).toBeDefined();
|
|
expect(stats.totalChecks).toBe(0);
|
|
expect(stats.coherentCount).toBe(0);
|
|
|
|
await service.dispose();
|
|
});
|
|
});
|
|
|
|
describe('MCP Tools Registration', () => {
|
|
it('should have all 4 coherence MCP tools registered', () => {
|
|
// Check tool names are defined
|
|
expect(COHERENCE_TOOL_NAMES.COHERENCE_CHECK).toBe('qe/coherence/check');
|
|
expect(COHERENCE_TOOL_NAMES.COHERENCE_AUDIT).toBe('qe/coherence/audit');
|
|
expect(COHERENCE_TOOL_NAMES.COHERENCE_CONSENSUS).toBe('qe/coherence/consensus');
|
|
expect(COHERENCE_TOOL_NAMES.COHERENCE_COLLAPSE).toBe('qe/coherence/collapse');
|
|
|
|
// Verify tools are in QE_TOOL_NAMES
|
|
expect(QE_TOOL_NAMES.COHERENCE_CHECK).toBe('qe/coherence/check');
|
|
expect(QE_TOOL_NAMES.COHERENCE_AUDIT).toBe('qe/coherence/audit');
|
|
expect(QE_TOOL_NAMES.COHERENCE_CONSENSUS).toBe('qe/coherence/consensus');
|
|
expect(QE_TOOL_NAMES.COHERENCE_COLLAPSE).toBe('qe/coherence/collapse');
|
|
});
|
|
|
|
it('should have coherence tools in QE_TOOLS array', () => {
|
|
const coherenceToolNames = [
|
|
'qe/coherence/check',
|
|
'qe/coherence/audit',
|
|
'qe/coherence/consensus',
|
|
'qe/coherence/collapse',
|
|
];
|
|
|
|
const registeredCoherenceTools = QE_TOOLS.filter((tool) =>
|
|
coherenceToolNames.includes(tool.name)
|
|
);
|
|
|
|
expect(registeredCoherenceTools).toHaveLength(4);
|
|
|
|
// Verify each tool has required properties
|
|
for (const tool of registeredCoherenceTools) {
|
|
expect(tool.name).toBeDefined();
|
|
expect(tool.description).toBeDefined();
|
|
expect(tool.domain).toBeDefined();
|
|
expect(typeof tool.invoke).toBe('function');
|
|
expect(typeof tool.getSchema).toBe('function');
|
|
}
|
|
});
|
|
|
|
it('should have correct domain for coherence tools', () => {
|
|
const coherenceToolNames = [
|
|
'qe/coherence/check',
|
|
'qe/coherence/audit',
|
|
'qe/coherence/consensus',
|
|
'qe/coherence/collapse',
|
|
];
|
|
|
|
const registeredCoherenceTools = QE_TOOLS.filter((tool) =>
|
|
coherenceToolNames.includes(tool.name)
|
|
);
|
|
|
|
for (const tool of registeredCoherenceTools) {
|
|
expect(tool.domain).toBe('learning-optimization');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('False Negative Rate - Contradiction Detection (0% allowed)', () => {
|
|
let service: CoherenceService;
|
|
|
|
beforeAll(async () => {
|
|
const mockLoader = createMockWasmLoader();
|
|
service = await createCoherenceService(mockLoader, {
|
|
fallbackEnabled: true,
|
|
coherenceThreshold: 0.1,
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await service.dispose();
|
|
});
|
|
|
|
it('should detect known contradictions - opposite embeddings', async () => {
|
|
const [embedding1, embedding2] = generateContradictoryEmbeddings();
|
|
|
|
const nodes: CoherenceNode[] = [
|
|
{ id: 'belief-true', embedding: embedding1 },
|
|
{ id: 'belief-false', embedding: embedding2 },
|
|
];
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// With fallback logic, opposite embeddings should produce high energy
|
|
// because they are maximally distant
|
|
expect(result).toBeDefined();
|
|
expect(result.energy).toBeGreaterThan(0); // Should have non-zero energy
|
|
// Note: In fallback mode, contradictions are detected based on distance > 1.5
|
|
});
|
|
|
|
it('should detect all contradictions from set of known contradictory pairs', async () => {
|
|
const contradictoryPairs = [
|
|
// Pair 1: Opposite direction
|
|
{
|
|
node1: { id: 'p1-a', embedding: generateRandomEmbedding(128, 1) },
|
|
node2: {
|
|
id: 'p1-b',
|
|
embedding: generateRandomEmbedding(128, 1).map((v) => -v),
|
|
},
|
|
},
|
|
// Pair 2: Different base, opposite
|
|
{
|
|
node1: { id: 'p2-a', embedding: generateRandomEmbedding(128, 2) },
|
|
node2: {
|
|
id: 'p2-b',
|
|
embedding: generateRandomEmbedding(128, 2).map((v) => -v),
|
|
},
|
|
},
|
|
// Pair 3: Different base, opposite
|
|
{
|
|
node1: { id: 'p3-a', embedding: generateRandomEmbedding(128, 3) },
|
|
node2: {
|
|
id: 'p3-b',
|
|
embedding: generateRandomEmbedding(128, 3).map((v) => -v),
|
|
},
|
|
},
|
|
];
|
|
|
|
let totalContradictions = 0;
|
|
const expectedContradictions = contradictoryPairs.length;
|
|
|
|
for (const pair of contradictoryPairs) {
|
|
const nodes: CoherenceNode[] = [pair.node1, pair.node2];
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// In fallback mode with opposite vectors, energy should be high
|
|
// (Euclidean distance between opposite unit vectors is 2.0)
|
|
if (result.energy > 0.5 || result.contradictions.length > 0) {
|
|
totalContradictions++;
|
|
}
|
|
}
|
|
|
|
// 100% detection rate required - all pairs should be flagged
|
|
expect(totalContradictions).toBe(expectedContradictions);
|
|
});
|
|
|
|
it('should detect contradictions with high distance embeddings', async () => {
|
|
// Create embeddings that are far apart in the embedding space
|
|
const embedding1 = new Array(128).fill(0).map((_, i) => (i < 64 ? 1 : 0));
|
|
const magnitude1 = Math.sqrt(embedding1.reduce((s, v) => s + v * v, 0));
|
|
const normalized1 = embedding1.map((v) => v / magnitude1);
|
|
|
|
const embedding2 = new Array(128).fill(0).map((_, i) => (i >= 64 ? 1 : 0));
|
|
const magnitude2 = Math.sqrt(embedding2.reduce((s, v) => s + v * v, 0));
|
|
const normalized2 = embedding2.map((v) => v / magnitude2);
|
|
|
|
const nodes: CoherenceNode[] = [
|
|
{ id: 'orthogonal-1', embedding: normalized1 },
|
|
{ id: 'orthogonal-2', embedding: normalized2 },
|
|
];
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// Orthogonal vectors should have distance sqrt(2) ~ 1.414
|
|
// With threshold 0.1, this should be detected as high energy
|
|
expect(result.energy).toBeGreaterThan(0.1);
|
|
});
|
|
});
|
|
|
|
describe('False Positive Rate - Coherent Input Validation (<5% allowed)', () => {
|
|
let service: CoherenceService;
|
|
|
|
beforeAll(async () => {
|
|
const mockLoader = createMockWasmLoader();
|
|
service = await createCoherenceService(mockLoader, {
|
|
fallbackEnabled: true,
|
|
coherenceThreshold: 0.4, // More lenient threshold for coherent inputs
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await service.dispose();
|
|
});
|
|
|
|
it('should not flag coherent inputs as contradictions', async () => {
|
|
const embeddings = generateCoherentEmbeddings(5);
|
|
|
|
const nodes: CoherenceNode[] = embeddings.map((emb, i) => ({
|
|
id: `coherent-${i}`,
|
|
embedding: emb,
|
|
}));
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// Coherent embeddings should have low energy
|
|
expect(result.energy).toBeLessThan(0.5);
|
|
// Should have no or few contradictions
|
|
expect(result.contradictions.length).toBeLessThanOrEqual(1);
|
|
});
|
|
|
|
it('should maintain <5% false positive rate across 100 coherent test cases', async () => {
|
|
const testCases = 100;
|
|
let falsePositives = 0;
|
|
|
|
for (let i = 0; i < testCases; i++) {
|
|
// Generate coherent embeddings for each test case
|
|
const embeddings = generateCoherentEmbeddings(3, 64);
|
|
|
|
const nodes: CoherenceNode[] = embeddings.map((emb, j) => ({
|
|
id: `test-${i}-node-${j}`,
|
|
embedding: emb,
|
|
}));
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// A false positive is when coherent inputs are flagged as incoherent
|
|
// with contradictions detected
|
|
if (result.contradictions.length > 0 && result.energy > 0.8) {
|
|
falsePositives++;
|
|
}
|
|
}
|
|
|
|
const falsePositiveRate = (falsePositives / testCases) * 100;
|
|
|
|
// Must be less than 5%
|
|
expect(falsePositiveRate).toBeLessThan(5);
|
|
});
|
|
|
|
it('should correctly identify identical embeddings as coherent', async () => {
|
|
const embedding = generateRandomEmbedding(128, 42);
|
|
|
|
const nodes: CoherenceNode[] = [
|
|
{ id: 'identical-1', embedding: [...embedding] },
|
|
{ id: 'identical-2', embedding: [...embedding] },
|
|
{ id: 'identical-3', embedding: [...embedding] },
|
|
];
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// Identical embeddings should have zero energy and no contradictions
|
|
expect(result.energy).toBe(0);
|
|
expect(result.contradictions).toHaveLength(0);
|
|
expect(result.isCoherent).toBe(true);
|
|
});
|
|
|
|
it('should handle single node as coherent', async () => {
|
|
const nodes: CoherenceNode[] = [
|
|
{ id: 'single', embedding: generateRandomEmbedding(128) },
|
|
];
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
expect(result.isCoherent).toBe(true);
|
|
expect(result.contradictions).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe('Coherence Service API Completeness', () => {
|
|
let service: CoherenceService;
|
|
|
|
beforeAll(async () => {
|
|
const mockLoader = createMockWasmLoader();
|
|
service = await createCoherenceService(mockLoader, {
|
|
fallbackEnabled: true,
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await service.dispose();
|
|
});
|
|
|
|
it('should have all required methods', () => {
|
|
expect(typeof service.checkCoherence).toBe('function');
|
|
expect(typeof service.detectContradictions).toBe('function');
|
|
expect(typeof service.predictCollapse).toBe('function');
|
|
expect(typeof service.verifyCausality).toBe('function');
|
|
expect(typeof service.verifyTypes).toBe('function');
|
|
expect(typeof service.createWitness).toBe('function');
|
|
expect(typeof service.replayFromWitness).toBe('function');
|
|
expect(typeof service.checkSwarmCoherence).toBe('function');
|
|
expect(typeof service.verifyConsensus).toBe('function');
|
|
expect(typeof service.filterCoherent).toBe('function');
|
|
expect(typeof service.getStats).toBe('function');
|
|
expect(typeof service.dispose).toBe('function');
|
|
});
|
|
|
|
it('should return correct lane based on energy', async () => {
|
|
// Test reflex lane (low energy)
|
|
const coherentEmbeddings = generateCoherentEmbeddings(2);
|
|
const nodes: CoherenceNode[] = coherentEmbeddings.map((emb, i) => ({
|
|
id: `lane-test-${i}`,
|
|
embedding: emb,
|
|
}));
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// With coherent embeddings, should get low energy lane
|
|
expect(['reflex', 'retrieval']).toContain(result.lane);
|
|
});
|
|
|
|
it('should track statistics correctly', async () => {
|
|
const initialStats = service.getStats();
|
|
const initialChecks = initialStats.totalChecks;
|
|
|
|
// Perform a check
|
|
const nodes: CoherenceNode[] = [
|
|
{ id: 'stats-test', embedding: generateRandomEmbedding(128) },
|
|
];
|
|
await service.checkCoherence(nodes);
|
|
|
|
const updatedStats = service.getStats();
|
|
expect(updatedStats.totalChecks).toBe(initialChecks + 1);
|
|
});
|
|
});
|
|
|
|
describe('Edge Cases and Robustness', () => {
|
|
let service: CoherenceService;
|
|
|
|
beforeAll(async () => {
|
|
const mockLoader = createMockWasmLoader();
|
|
service = await createCoherenceService(mockLoader, {
|
|
fallbackEnabled: true,
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await service.dispose();
|
|
});
|
|
|
|
it('should handle empty node list gracefully', async () => {
|
|
const nodes: CoherenceNode[] = [];
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
expect(result).toBeDefined();
|
|
expect(result.isCoherent).toBe(true);
|
|
expect(result.contradictions).toHaveLength(0);
|
|
});
|
|
|
|
it('should handle very small embeddings', async () => {
|
|
const nodes: CoherenceNode[] = [
|
|
{ id: 'small-1', embedding: [0.5, 0.5] },
|
|
{ id: 'small-2', embedding: [0.6, 0.4] },
|
|
];
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
expect(result).toBeDefined();
|
|
});
|
|
|
|
it('should handle large number of nodes', async () => {
|
|
const nodes: CoherenceNode[] = Array.from({ length: 50 }, (_, i) => ({
|
|
id: `bulk-${i}`,
|
|
embedding: generateRandomEmbedding(32, i),
|
|
}));
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
expect(result).toBeDefined();
|
|
expect(result.durationMs).toBeDefined();
|
|
});
|
|
|
|
it('should report fallback usage correctly', async () => {
|
|
const nodes: CoherenceNode[] = [
|
|
{ id: 'fallback-test', embedding: generateRandomEmbedding(128) },
|
|
];
|
|
|
|
const result = await service.checkCoherence(nodes);
|
|
|
|
// With mock loader returning false for isAvailable, fallback should be used
|
|
expect(result.usedFallback).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
// ============================================================================
|
|
// Summary
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Test Summary for ADR-052 A4.5 Quality Gates:
|
|
*
|
|
* 1. Engine Adapter Functionality:
|
|
* - All 6 adapters (Cohomology, Spectral, Causal, Category, Homotopy, Witness)
|
|
* - Can be instantiated without errors
|
|
*
|
|
* 2. CoherenceService Initialization:
|
|
* - Successfully initializes with fallback enabled
|
|
* - Tracks statistics correctly
|
|
*
|
|
* 3. MCP Tools Registration:
|
|
* - 4 tools registered: check, audit, consensus, collapse
|
|
* - Tools have correct names and domains
|
|
*
|
|
* 4. False Negative Rate (0% allowed):
|
|
* - Known contradictions (opposite embeddings) are detected
|
|
* - All contradictory pairs in test set are flagged
|
|
*
|
|
* 5. False Positive Rate (<5% allowed):
|
|
* - Coherent embeddings are not flagged as contradictions
|
|
* - 100 coherent test cases with <5% false positives
|
|
*/
|