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>
6.8 KiB
6.8 KiB
SPEC-035-A: Causal Weight Matrix
| Field | Value |
|---|---|
| Specification ID | SPEC-035-A |
| Parent ADR | ADR-035 |
| Version | 1.0 |
| Status | Draft |
| Last Updated | 2026-01-20 |
| Author | Architecture Team |
Overview
This specification defines the Causal Weight Matrix that learns causal relationships between test events using asymmetric STDP (Spike-Timing Dependent Plasticity) rules. The matrix tracks timing relationships to infer which events cause others.
Configuration
export interface CausalDiscoveryConfig {
/** Number of event types to track */
numEventTypes: number;
/** Threshold for significant causal relationship */
causalThreshold: number;
/** Time window for causality detection (ms) */
timeWindow: number;
/** Learning rate for causal weight updates */
learningRate: number;
/** Decay rate for causal weights */
decayRate: number;
}
export const DEFAULT_CAUSAL_CONFIG: CausalDiscoveryConfig = {
numEventTypes: 100,
causalThreshold: 0.1,
timeWindow: 50,
learningRate: 0.01,
decayRate: 0.001,
};
Event Types
export type TestEventType =
| 'test_started'
| 'test_passed'
| 'test_failed'
| 'test_flaky'
| 'assertion_failed'
| 'timeout'
| 'exception'
| 'resource_exhausted'
| 'dependency_failed'
| 'coverage_changed'
| 'build_failed'
| 'deploy_started'
| 'deploy_failed'
| 'deploy_succeeded'
| 'rollback_triggered'
| 'alert_fired';
export interface TestEvent {
/** Type of event */
type: TestEventType;
/** Timestamp in milliseconds */
timestamp: number;
/** Associated test ID (if applicable) */
testId?: string;
/** Associated file path (if applicable) */
file?: string;
/** Event metadata */
data?: Record<string, unknown>;
}
Causal Relationship Types
export type CausalRelation = 'causes' | 'prevents' | 'none';
export interface CausalEdge {
source: TestEventType;
target: TestEventType;
strength: number;
relation: CausalRelation;
}
export interface CausalGraph {
nodes: TestEventType[];
edges: CausalEdge[];
/** Get all edges from a source event */
edgesFrom(source: TestEventType): CausalEdge[];
/** Get all edges to a target event */
edgesTo(target: TestEventType): CausalEdge[];
/** Find reachable nodes from a source */
reachableFrom(source: TestEventType): Set<TestEventType>;
/** Compute transitive closure */
transitiveClosure(): CausalGraph;
}
CausalWeightMatrix Implementation
export class CausalWeightMatrix {
private weights: Map<string, number> = new Map();
private lastSpikeTime: Map<TestEventType, number> = new Map();
constructor(private config: CausalDiscoveryConfig) {}
/** Get causal weight from source to target */
getWeight(source: TestEventType, target: TestEventType): number {
return this.weights.get(`${source}->${target}`) || 0;
}
/** Set causal weight */
setWeight(source: TestEventType, target: TestEventType, weight: number): void {
this.weights.set(`${source}->${target}`, weight);
}
/** Update weights using asymmetric STDP rule */
updateWeights(event: TestEvent): void {
const currentTime = event.timestamp;
const currentType = event.type;
// Update weights based on timing relative to all other event types
for (const [otherType, lastTime] of this.lastSpikeTime.entries()) {
const dt = currentTime - lastTime;
if (dt > 0 && dt < this.config.timeWindow) {
// Other event preceded this one -> otherType may cause currentType
const weightChange = this.stdpPositive(dt);
const currentWeight = this.getWeight(otherType, currentType);
this.setWeight(otherType, currentType, currentWeight + weightChange);
} else if (dt < 0 && Math.abs(dt) < this.config.timeWindow) {
// This event preceded other -> currentType may cause otherType
const weightChange = this.stdpNegative(Math.abs(dt));
const currentWeight = this.getWeight(currentType, otherType);
this.setWeight(currentType, otherType, currentWeight + weightChange);
}
}
// Record this event's time
this.lastSpikeTime.set(currentType, currentTime);
}
/** STDP: positive timing (pre before post) strengthens connection */
private stdpPositive(dt: number): number {
const tau = this.config.timeWindow / 3;
return this.config.learningRate * Math.exp(-dt / tau);
}
/** STDP: negative timing (post before pre) weakens connection */
private stdpNegative(dt: number): number {
const tau = this.config.timeWindow / 3;
return -0.5 * this.config.learningRate * Math.exp(-dt / tau);
}
/** Apply decay to all weights */
decay(): void {
for (const [key, weight] of this.weights.entries()) {
const decayedWeight = weight * (1 - this.config.decayRate);
if (Math.abs(decayedWeight) < 0.001) {
this.weights.delete(key);
} else {
this.weights.set(key, decayedWeight);
}
}
}
/** Extract causal graph from learned weights */
extractCausalGraph(): CausalGraph {
const nodes = new Set<TestEventType>();
const edges: CausalEdge[] = [];
for (const [key, weight] of this.weights.entries()) {
const [source, target] = key.split('->') as [TestEventType, TestEventType];
if (Math.abs(weight) > this.config.causalThreshold) {
nodes.add(source);
nodes.add(target);
edges.push({
source,
target,
strength: Math.abs(weight),
relation: weight > 0 ? 'causes' : 'prevents',
});
}
}
return new CausalGraphImpl(Array.from(nodes), edges);
}
}
Validation Rules
| Rule ID | Description | Severity |
|---|---|---|
| SPEC-035-A-001 | timeWindow must be > 0 | Error |
| SPEC-035-A-002 | learningRate must be 0-1 | Warning |
| SPEC-035-A-003 | decayRate must be 0-1 | Warning |
| SPEC-035-A-004 | causalThreshold must be >= 0 | Error |
Related Specifications
| Spec ID | Title | Relationship |
|---|---|---|
| SPEC-035-B | Causal Graph | Uses weight matrix |
| SPEC-035-C | Discovery Engine | Orchestrates learning |
Changelog
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2026-01-20 | Architecture Team | Initial specification |