Files
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

289 lines
8.4 KiB
Markdown

# SPEC-035-C: Causal Discovery Engine
| Field | Value |
|-------|-------|
| **Specification ID** | SPEC-035-C |
| **Parent ADR** | [ADR-035](../adrs/ADR-035-causal-discovery.md) |
| **Version** | 1.0 |
| **Status** | Draft |
| **Last Updated** | 2026-01-20 |
| **Author** | Architecture Team |
---
## Overview
This specification defines the Causal Discovery Engine that orchestrates event observation, weight learning, and root cause analysis. It provides the main API for integrating causal discovery with defect intelligence.
---
## CausalDiscoveryEngine Implementation
```typescript
export class CausalDiscoveryEngine {
private weightMatrix: CausalWeightMatrix;
private eventHistory: TestEvent[] = [];
private config: CausalDiscoveryConfig;
constructor(config: CausalDiscoveryConfig = DEFAULT_CAUSAL_CONFIG) {
this.config = config;
this.weightMatrix = new CausalWeightMatrix(config);
}
/** Observe a test event */
observe(event: TestEvent): void {
this.weightMatrix.updateWeights(event);
this.eventHistory.push(event);
// Prune old events
const cutoff = event.timestamp - this.config.timeWindow * 100;
this.eventHistory = this.eventHistory.filter(e => e.timestamp > cutoff);
}
/** Observe multiple events */
observeBatch(events: TestEvent[]): void {
for (const event of events) {
this.observe(event);
}
}
/** Perform root cause analysis for a target event */
analyzeRootCause(targetEvent: TestEventType): RootCauseAnalysis {
const graph = this.weightMatrix.extractCausalGraph();
// Find direct causes
const directCauses = graph.edgesTo(targetEvent)
.map(e => ({ event: e.source, strength: e.strength }))
.sort((a, b) => b.strength - a.strength);
// Find indirect causes via transitive closure
const closedGraph = graph.transitiveClosure();
const indirectCauses: Array<{ event: TestEventType; strength: number; path: TestEventType[] }> = [];
for (const edge of closedGraph.edgesTo(targetEvent)) {
// Skip if it's a direct cause
if (directCauses.some(dc => dc.event === edge.source)) continue;
indirectCauses.push({
event: edge.source,
strength: edge.strength,
path: this.findPath(graph, edge.source, targetEvent),
});
}
indirectCauses.sort((a, b) => b.strength - a.strength);
// Find optimal intervention points
const interventionPoints = this.findInterventionPoints(graph, targetEvent);
// Calculate confidence based on evidence strength
const totalEvidence = [...directCauses, ...indirectCauses]
.reduce((sum, c) => sum + c.strength, 0);
const confidence = Math.min(totalEvidence / 5, 1);
return {
targetEvent,
directCauses,
indirectCauses,
interventionPoints,
confidence,
};
}
/** Find path from source to target */
private findPath(graph: CausalGraph, source: TestEventType, target: TestEventType): TestEventType[] {
const visited = new Set<TestEventType>();
const parent = new Map<TestEventType, TestEventType>();
const queue: TestEventType[] = [source];
while (queue.length > 0) {
const current = queue.shift()!;
if (current === target) break;
if (visited.has(current)) continue;
visited.add(current);
for (const edge of graph.edgesFrom(current)) {
if (!visited.has(edge.target)) {
parent.set(edge.target, current);
queue.push(edge.target);
}
}
}
// Reconstruct path
const path: TestEventType[] = [];
let current: TestEventType | undefined = target;
while (current && current !== source) {
path.unshift(current);
current = parent.get(current);
}
if (current === source) {
path.unshift(source);
}
return path;
}
/** Find optimal intervention points (mincut on causal graph) */
private findInterventionPoints(graph: CausalGraph, target: TestEventType): TestEventType[] {
// Heuristic: nodes with high out-degree that can reach target
const reachability = new Map<TestEventType, number>();
for (const node of graph.nodes) {
const reachable = graph.reachableFrom(node);
if (reachable.has(target)) {
const outDegree = graph.edgesFrom(node).length;
reachability.set(node, outDegree);
}
}
// Sort by out-degree and return top 5
return Array.from(reachability.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 5)
.map(([node]) => node);
}
/** Get all learned causal relationships */
getCausalGraph(): CausalGraph {
return this.weightMatrix.extractCausalGraph();
}
/** Get summary statistics */
getSummary(): CausalSummary {
const graph = this.weightMatrix.extractCausalGraph();
let causesCount = 0;
let preventsCount = 0;
let totalStrength = 0;
for (const edge of graph.edges) {
totalStrength += edge.strength;
if (edge.relation === 'causes') causesCount++;
if (edge.relation === 'prevents') preventsCount++;
}
return {
numRelationships: graph.edges.length,
causesCount,
preventsCount,
avgStrength: graph.edges.length > 0 ? totalStrength / graph.edges.length : 0,
eventsObserved: this.eventHistory.length,
};
}
/** Apply decay to learned weights */
decay(): void {
this.weightMatrix.decay();
}
/** Reset all learned relationships */
reset(): void {
this.weightMatrix = new CausalWeightMatrix(this.config);
this.eventHistory = [];
}
}
```
---
## Defect Intelligence Integration
```typescript
// In defect-intelligence domain
import { CausalDiscoveryEngine, RootCauseAnalysis } from '../causal-discovery';
export class DefectIntelligenceService {
private causalEngine: CausalDiscoveryEngine;
constructor() {
this.causalEngine = new CausalDiscoveryEngine();
}
/** Called when any test event occurs */
onTestEvent(event: TestEvent): void {
this.causalEngine.observe(event);
}
/** Analyze root cause of test failures */
analyzeTestFailure(failedTestId: string): RootCauseAnalysis {
const analysis = this.causalEngine.analyzeRootCause('test_failed');
console.log(`[Defect Intelligence] Root cause analysis for ${failedTestId}:`);
console.log(` Direct causes: ${analysis.directCauses.map(c => c.event).join(', ')}`);
console.log(` Intervention points: ${analysis.interventionPoints.join(', ')}`);
return analysis;
}
/** Predict which events might cause future failures */
predictFailures(): TestEventType[] {
const graph = this.causalEngine.getCausalGraph();
return graph.edgesTo('test_failed')
.filter(e => e.strength > 0.5)
.map(e => e.source);
}
}
```
---
## Implementation Plan
### Phase 1: Core Causal Discovery (Days 1-2)
```
v3/src/causal-discovery/
├── index.ts
├── types.ts
├── weight-matrix.ts # CausalWeightMatrix
├── causal-graph.ts # CausalGraph implementation
└── discovery-engine.ts # CausalDiscoveryEngine
```
### Phase 2: Root Cause Analysis (Days 3-4)
```
├── root-cause-analyzer.ts # RootCauseAnalysis logic
├── intervention-finder.ts # Optimal intervention points
└── path-finder.ts # Causal path discovery
```
### Phase 3: Integration (Day 5)
- Integrate with defect-intelligence domain
- Add MCP tool for causal analysis
- Create visualization dashboard
---
## Validation Rules
| Rule ID | Description | Severity |
|---------|-------------|----------|
| SPEC-035-C-001 | Events must have valid timestamps | Error |
| SPEC-035-C-002 | Event type must be valid TestEventType | Error |
| SPEC-035-C-003 | Batch events should be sorted by timestamp | Warning |
---
## Related Specifications
| Spec ID | Title | Relationship |
|---------|-------|--------------|
| SPEC-035-A | Causal Weight Matrix | Core learning component |
| SPEC-035-B | Causal Graph | Graph representation |
---
## Changelog
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2026-01-20 | Architecture Team | Initial specification |
---
## References
- [Parent ADR](../adrs/ADR-035-causal-discovery.md)
- [Causal Discovery in Machine Learning](https://arxiv.org/abs/2206.15475)