@timmeck/brain-core 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/causal/engine.d.ts +98 -0
- package/dist/causal/engine.js +265 -0
- package/dist/causal/engine.js.map +1 -0
- package/dist/hypothesis/engine.d.ts +104 -0
- package/dist/hypothesis/engine.js +386 -0
- package/dist/hypothesis/engine.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/meta-learning/engine.d.ts +108 -0
- package/dist/meta-learning/engine.js +275 -0
- package/dist/meta-learning/engine.js.map +1 -0
- package/package.json +5 -2
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
export interface CausalEvent {
|
|
3
|
+
source: string;
|
|
4
|
+
type: string;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
data?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface CausalEdge {
|
|
9
|
+
id?: number;
|
|
10
|
+
cause: string;
|
|
11
|
+
effect: string;
|
|
12
|
+
strength: number;
|
|
13
|
+
confidence: number;
|
|
14
|
+
lag_ms: number;
|
|
15
|
+
sample_size: number;
|
|
16
|
+
direction: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CausalPath {
|
|
19
|
+
chain: string[];
|
|
20
|
+
totalStrength: number;
|
|
21
|
+
totalLag: number;
|
|
22
|
+
}
|
|
23
|
+
export interface CausalAnalysis {
|
|
24
|
+
edges: CausalEdge[];
|
|
25
|
+
roots: string[];
|
|
26
|
+
leaves: string[];
|
|
27
|
+
strongestChain: CausalPath | null;
|
|
28
|
+
}
|
|
29
|
+
export declare function runCausalMigration(db: Database.Database): void;
|
|
30
|
+
/**
|
|
31
|
+
* Causal Inference Engine: detects cause→effect relationships between events.
|
|
32
|
+
*
|
|
33
|
+
* Research approach: Simplified Granger Causality.
|
|
34
|
+
*
|
|
35
|
+
* Granger causality asks: "Does knowing that event A happened improve
|
|
36
|
+
* our ability to predict event B?" If yes, A Granger-causes B.
|
|
37
|
+
*
|
|
38
|
+
* Algorithm:
|
|
39
|
+
* 1. Record all events with timestamps
|
|
40
|
+
* 2. For each pair of event types (A, B):
|
|
41
|
+
* a. Count how often B occurs within a time window after A
|
|
42
|
+
* b. Compare this to the baseline rate of B
|
|
43
|
+
* c. If B is significantly more likely after A → A causes B
|
|
44
|
+
* 3. Build a directed graph of causal relationships
|
|
45
|
+
* 4. Detect causal chains (A → B → C)
|
|
46
|
+
*/
|
|
47
|
+
export declare class CausalGraph {
|
|
48
|
+
private db;
|
|
49
|
+
private logger;
|
|
50
|
+
private maxWindowMs;
|
|
51
|
+
private minSamples;
|
|
52
|
+
private significanceThreshold;
|
|
53
|
+
constructor(db: Database.Database, config?: {
|
|
54
|
+
maxWindowMs?: number;
|
|
55
|
+
minSamples?: number;
|
|
56
|
+
significanceThreshold?: number;
|
|
57
|
+
});
|
|
58
|
+
/** Record an event for causal analysis. */
|
|
59
|
+
recordEvent(source: string, type: string, data?: unknown): void;
|
|
60
|
+
/**
|
|
61
|
+
* Run Granger causality analysis on all event pairs.
|
|
62
|
+
* This is the core research algorithm.
|
|
63
|
+
*/
|
|
64
|
+
analyze(): CausalEdge[];
|
|
65
|
+
/**
|
|
66
|
+
* Test if event type A Granger-causes event type B.
|
|
67
|
+
*
|
|
68
|
+
* Algorithm:
|
|
69
|
+
* 1. Get all timestamps for A and B
|
|
70
|
+
* 2. For each occurrence of A, check if B occurs within the window after
|
|
71
|
+
* 3. Calculate: P(B after A) vs P(B in any random window)
|
|
72
|
+
* 4. If ratio > threshold → A Granger-causes B
|
|
73
|
+
*/
|
|
74
|
+
private testGrangerCausality;
|
|
75
|
+
/** Get all detected causal edges (strongest first). */
|
|
76
|
+
getEdges(minStrength?: number): CausalEdge[];
|
|
77
|
+
/** Get causes of a specific event type. */
|
|
78
|
+
getCauses(eventType: string): CausalEdge[];
|
|
79
|
+
/** Get effects of a specific event type. */
|
|
80
|
+
getEffects(eventType: string): CausalEdge[];
|
|
81
|
+
/** Find causal chains (A → B → C). */
|
|
82
|
+
findChains(maxDepth?: number): CausalPath[];
|
|
83
|
+
/** Full causal analysis including graph structure. */
|
|
84
|
+
getAnalysis(): CausalAnalysis;
|
|
85
|
+
/** Get event type statistics. */
|
|
86
|
+
getEventStats(): Array<{
|
|
87
|
+
type: string;
|
|
88
|
+
count: number;
|
|
89
|
+
first_seen: number;
|
|
90
|
+
last_seen: number;
|
|
91
|
+
}>;
|
|
92
|
+
private getEventTypes;
|
|
93
|
+
private getTimeRange;
|
|
94
|
+
private upsertEdge;
|
|
95
|
+
private findRoots;
|
|
96
|
+
private findLeaves;
|
|
97
|
+
private dfs;
|
|
98
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
// ── Migration ───────────────────────────────────────────
|
|
3
|
+
export function runCausalMigration(db) {
|
|
4
|
+
db.exec(`
|
|
5
|
+
CREATE TABLE IF NOT EXISTS causal_events (
|
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
source TEXT NOT NULL,
|
|
8
|
+
type TEXT NOT NULL,
|
|
9
|
+
timestamp INTEGER NOT NULL,
|
|
10
|
+
data TEXT,
|
|
11
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS causal_edges (
|
|
15
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
|
+
cause TEXT NOT NULL,
|
|
17
|
+
effect TEXT NOT NULL,
|
|
18
|
+
strength REAL NOT NULL DEFAULT 0,
|
|
19
|
+
confidence REAL NOT NULL DEFAULT 0,
|
|
20
|
+
lag_ms REAL NOT NULL DEFAULT 0,
|
|
21
|
+
sample_size INTEGER NOT NULL DEFAULT 0,
|
|
22
|
+
direction REAL NOT NULL DEFAULT 1,
|
|
23
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
24
|
+
UNIQUE(cause, effect)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE INDEX IF NOT EXISTS idx_causal_events_type ON causal_events(type);
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_causal_events_timestamp ON causal_events(timestamp);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_causal_edges_strength ON causal_edges(strength DESC);
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
// ── Engine ───────────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* Causal Inference Engine: detects cause→effect relationships between events.
|
|
35
|
+
*
|
|
36
|
+
* Research approach: Simplified Granger Causality.
|
|
37
|
+
*
|
|
38
|
+
* Granger causality asks: "Does knowing that event A happened improve
|
|
39
|
+
* our ability to predict event B?" If yes, A Granger-causes B.
|
|
40
|
+
*
|
|
41
|
+
* Algorithm:
|
|
42
|
+
* 1. Record all events with timestamps
|
|
43
|
+
* 2. For each pair of event types (A, B):
|
|
44
|
+
* a. Count how often B occurs within a time window after A
|
|
45
|
+
* b. Compare this to the baseline rate of B
|
|
46
|
+
* c. If B is significantly more likely after A → A causes B
|
|
47
|
+
* 3. Build a directed graph of causal relationships
|
|
48
|
+
* 4. Detect causal chains (A → B → C)
|
|
49
|
+
*/
|
|
50
|
+
export class CausalGraph {
|
|
51
|
+
db;
|
|
52
|
+
logger = getLogger();
|
|
53
|
+
maxWindowMs; // max time lag to consider
|
|
54
|
+
minSamples; // minimum observations for significance
|
|
55
|
+
significanceThreshold; // minimum ratio to baseline for significance
|
|
56
|
+
constructor(db, config) {
|
|
57
|
+
this.db = db;
|
|
58
|
+
runCausalMigration(db);
|
|
59
|
+
this.maxWindowMs = config?.maxWindowMs ?? 300_000; // 5 minutes
|
|
60
|
+
this.minSamples = config?.minSamples ?? 5;
|
|
61
|
+
this.significanceThreshold = config?.significanceThreshold ?? 1.5; // 50% above baseline
|
|
62
|
+
}
|
|
63
|
+
/** Record an event for causal analysis. */
|
|
64
|
+
recordEvent(source, type, data) {
|
|
65
|
+
this.db.prepare(`
|
|
66
|
+
INSERT INTO causal_events (source, type, timestamp, data)
|
|
67
|
+
VALUES (?, ?, ?, ?)
|
|
68
|
+
`).run(source, type, Date.now(), data ? JSON.stringify(data) : null);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Run Granger causality analysis on all event pairs.
|
|
72
|
+
* This is the core research algorithm.
|
|
73
|
+
*/
|
|
74
|
+
analyze() {
|
|
75
|
+
const eventTypes = this.getEventTypes();
|
|
76
|
+
if (eventTypes.length < 2)
|
|
77
|
+
return [];
|
|
78
|
+
const edges = [];
|
|
79
|
+
// For each pair of event types, test for Granger causality
|
|
80
|
+
for (const cause of eventTypes) {
|
|
81
|
+
for (const effect of eventTypes) {
|
|
82
|
+
if (cause === effect)
|
|
83
|
+
continue;
|
|
84
|
+
const edge = this.testGrangerCausality(cause, effect);
|
|
85
|
+
if (edge) {
|
|
86
|
+
this.upsertEdge(edge);
|
|
87
|
+
edges.push(edge);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
this.logger.info(`Causal analysis complete: ${edges.length} causal relationships detected`);
|
|
92
|
+
return edges;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Test if event type A Granger-causes event type B.
|
|
96
|
+
*
|
|
97
|
+
* Algorithm:
|
|
98
|
+
* 1. Get all timestamps for A and B
|
|
99
|
+
* 2. For each occurrence of A, check if B occurs within the window after
|
|
100
|
+
* 3. Calculate: P(B after A) vs P(B in any random window)
|
|
101
|
+
* 4. If ratio > threshold → A Granger-causes B
|
|
102
|
+
*/
|
|
103
|
+
testGrangerCausality(causeType, effectType) {
|
|
104
|
+
const causeEvents = this.db.prepare('SELECT timestamp FROM causal_events WHERE type = ? ORDER BY timestamp').all(causeType);
|
|
105
|
+
const effectEvents = this.db.prepare('SELECT timestamp FROM causal_events WHERE type = ? ORDER BY timestamp').all(effectType);
|
|
106
|
+
if (causeEvents.length < this.minSamples || effectEvents.length < this.minSamples) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
// Calculate: how often does effectType occur within maxWindowMs after causeType?
|
|
110
|
+
let followCount = 0;
|
|
111
|
+
let totalLag = 0;
|
|
112
|
+
for (const cause of causeEvents) {
|
|
113
|
+
// Find the first effect event within the window
|
|
114
|
+
for (const effect of effectEvents) {
|
|
115
|
+
const lag = effect.timestamp - cause.timestamp;
|
|
116
|
+
if (lag > 0 && lag <= this.maxWindowMs) {
|
|
117
|
+
followCount++;
|
|
118
|
+
totalLag += lag;
|
|
119
|
+
break; // only count first occurrence per cause event
|
|
120
|
+
}
|
|
121
|
+
if (lag > this.maxWindowMs)
|
|
122
|
+
break; // past window, stop looking
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (followCount < this.minSamples)
|
|
126
|
+
return null;
|
|
127
|
+
// P(effect follows cause) = followCount / causeEvents.length
|
|
128
|
+
const pFollows = followCount / causeEvents.length;
|
|
129
|
+
// Baseline: P(effect in any random window of same size)
|
|
130
|
+
// Estimate: total effect events / total time * window size
|
|
131
|
+
const timeRange = this.getTimeRange();
|
|
132
|
+
if (timeRange <= 0)
|
|
133
|
+
return null;
|
|
134
|
+
const baselineRate = (effectEvents.length / timeRange) * this.maxWindowMs;
|
|
135
|
+
const pBaseline = Math.min(1, baselineRate);
|
|
136
|
+
// Significance: is the conditional probability significantly higher than baseline?
|
|
137
|
+
if (pBaseline <= 0)
|
|
138
|
+
return null;
|
|
139
|
+
const ratio = pFollows / pBaseline;
|
|
140
|
+
if (ratio < this.significanceThreshold)
|
|
141
|
+
return null;
|
|
142
|
+
// Calculate strength (0-1 normalized)
|
|
143
|
+
const strength = Math.min(1, (ratio - 1) / (this.significanceThreshold * 2));
|
|
144
|
+
// Confidence based on sample size (logistic curve, plateaus around 20 samples)
|
|
145
|
+
const confidence = 1 - 1 / (1 + followCount / 10);
|
|
146
|
+
// Average lag
|
|
147
|
+
const avgLag = followCount > 0 ? totalLag / followCount : 0;
|
|
148
|
+
return {
|
|
149
|
+
cause: causeType,
|
|
150
|
+
effect: effectType,
|
|
151
|
+
strength,
|
|
152
|
+
confidence,
|
|
153
|
+
lag_ms: avgLag,
|
|
154
|
+
sample_size: followCount,
|
|
155
|
+
direction: 1, // cause increases likelihood of effect
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/** Get all detected causal edges (strongest first). */
|
|
159
|
+
getEdges(minStrength = 0) {
|
|
160
|
+
return this.db.prepare('SELECT * FROM causal_edges WHERE strength >= ? ORDER BY strength DESC').all(minStrength);
|
|
161
|
+
}
|
|
162
|
+
/** Get causes of a specific event type. */
|
|
163
|
+
getCauses(eventType) {
|
|
164
|
+
return this.db.prepare('SELECT * FROM causal_edges WHERE effect = ? ORDER BY strength DESC').all(eventType);
|
|
165
|
+
}
|
|
166
|
+
/** Get effects of a specific event type. */
|
|
167
|
+
getEffects(eventType) {
|
|
168
|
+
return this.db.prepare('SELECT * FROM causal_edges WHERE cause = ? ORDER BY strength DESC').all(eventType);
|
|
169
|
+
}
|
|
170
|
+
/** Find causal chains (A → B → C). */
|
|
171
|
+
findChains(maxDepth = 4) {
|
|
172
|
+
const edges = this.getEdges(0.1);
|
|
173
|
+
const adjacency = new Map();
|
|
174
|
+
for (const edge of edges) {
|
|
175
|
+
if (!adjacency.has(edge.cause))
|
|
176
|
+
adjacency.set(edge.cause, []);
|
|
177
|
+
adjacency.get(edge.cause).push(edge);
|
|
178
|
+
}
|
|
179
|
+
const chains = [];
|
|
180
|
+
const roots = this.findRoots(edges);
|
|
181
|
+
for (const root of roots) {
|
|
182
|
+
this.dfs(root, [root], 0, 0, adjacency, maxDepth, new Set(), chains);
|
|
183
|
+
}
|
|
184
|
+
// Sort by total strength descending
|
|
185
|
+
chains.sort((a, b) => b.totalStrength - a.totalStrength);
|
|
186
|
+
return chains.slice(0, 20); // top 20 chains
|
|
187
|
+
}
|
|
188
|
+
/** Full causal analysis including graph structure. */
|
|
189
|
+
getAnalysis() {
|
|
190
|
+
const edges = this.getEdges();
|
|
191
|
+
const roots = this.findRoots(edges);
|
|
192
|
+
const leaves = this.findLeaves(edges);
|
|
193
|
+
const chains = this.findChains();
|
|
194
|
+
return {
|
|
195
|
+
edges,
|
|
196
|
+
roots,
|
|
197
|
+
leaves,
|
|
198
|
+
strongestChain: chains.length > 0 ? chains[0] : null,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/** Get event type statistics. */
|
|
202
|
+
getEventStats() {
|
|
203
|
+
return this.db.prepare(`
|
|
204
|
+
SELECT type, COUNT(*) as count,
|
|
205
|
+
MIN(timestamp) as first_seen,
|
|
206
|
+
MAX(timestamp) as last_seen
|
|
207
|
+
FROM causal_events
|
|
208
|
+
GROUP BY type
|
|
209
|
+
ORDER BY count DESC
|
|
210
|
+
`).all();
|
|
211
|
+
}
|
|
212
|
+
// ── Private helpers ─────────────────────────────────
|
|
213
|
+
getEventTypes() {
|
|
214
|
+
const rows = this.db.prepare('SELECT DISTINCT type FROM causal_events').all();
|
|
215
|
+
return rows.map(r => r.type);
|
|
216
|
+
}
|
|
217
|
+
getTimeRange() {
|
|
218
|
+
const row = this.db.prepare('SELECT MIN(timestamp) as min_ts, MAX(timestamp) as max_ts FROM causal_events').get();
|
|
219
|
+
if (!row.min_ts || !row.max_ts)
|
|
220
|
+
return 0;
|
|
221
|
+
return row.max_ts - row.min_ts;
|
|
222
|
+
}
|
|
223
|
+
upsertEdge(edge) {
|
|
224
|
+
this.db.prepare(`
|
|
225
|
+
INSERT INTO causal_edges (cause, effect, strength, confidence, lag_ms, sample_size, direction)
|
|
226
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
227
|
+
ON CONFLICT(cause, effect) DO UPDATE SET
|
|
228
|
+
strength = ?, confidence = ?, lag_ms = ?, sample_size = ?, direction = ?,
|
|
229
|
+
updated_at = datetime('now')
|
|
230
|
+
`).run(edge.cause, edge.effect, edge.strength, edge.confidence, edge.lag_ms, edge.sample_size, edge.direction, edge.strength, edge.confidence, edge.lag_ms, edge.sample_size, edge.direction);
|
|
231
|
+
}
|
|
232
|
+
findRoots(edges) {
|
|
233
|
+
const causes = new Set(edges.map(e => e.cause));
|
|
234
|
+
const effects = new Set(edges.map(e => e.effect));
|
|
235
|
+
return [...causes].filter(c => !effects.has(c));
|
|
236
|
+
}
|
|
237
|
+
findLeaves(edges) {
|
|
238
|
+
const causes = new Set(edges.map(e => e.cause));
|
|
239
|
+
const effects = new Set(edges.map(e => e.effect));
|
|
240
|
+
return [...effects].filter(e => !causes.has(e));
|
|
241
|
+
}
|
|
242
|
+
dfs(node, path, totalStrength, totalLag, adjacency, maxDepth, visited, results) {
|
|
243
|
+
if (path.length >= 3) {
|
|
244
|
+
// Record any path of length 3+ as a chain
|
|
245
|
+
results.push({
|
|
246
|
+
chain: [...path],
|
|
247
|
+
totalStrength: totalStrength / (path.length - 1), // average strength
|
|
248
|
+
totalLag,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (path.length >= maxDepth)
|
|
252
|
+
return;
|
|
253
|
+
const neighbors = adjacency.get(node) ?? [];
|
|
254
|
+
for (const edge of neighbors) {
|
|
255
|
+
if (visited.has(edge.effect))
|
|
256
|
+
continue;
|
|
257
|
+
visited.add(edge.effect);
|
|
258
|
+
path.push(edge.effect);
|
|
259
|
+
this.dfs(edge.effect, path, totalStrength + edge.strength, totalLag + edge.lag_ms, adjacency, maxDepth, visited, results);
|
|
260
|
+
path.pop();
|
|
261
|
+
visited.delete(edge.effect);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/causal/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
export type HypothesisStatus = 'proposed' | 'testing' | 'confirmed' | 'rejected' | 'inconclusive';
|
|
3
|
+
export interface Hypothesis {
|
|
4
|
+
id?: number;
|
|
5
|
+
statement: string;
|
|
6
|
+
type: string;
|
|
7
|
+
source: string;
|
|
8
|
+
variables: string[];
|
|
9
|
+
condition: HypothesisCondition;
|
|
10
|
+
status: HypothesisStatus;
|
|
11
|
+
evidence_for: number;
|
|
12
|
+
evidence_against: number;
|
|
13
|
+
confidence: number;
|
|
14
|
+
p_value: number;
|
|
15
|
+
created_at?: string;
|
|
16
|
+
tested_at?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface HypothesisCondition {
|
|
19
|
+
type: 'temporal' | 'correlation' | 'threshold' | 'frequency';
|
|
20
|
+
params: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
export interface HypothesisTestResult {
|
|
23
|
+
hypothesisId: number;
|
|
24
|
+
passed: boolean;
|
|
25
|
+
evidenceFor: number;
|
|
26
|
+
evidenceAgainst: number;
|
|
27
|
+
pValue: number;
|
|
28
|
+
confidence: number;
|
|
29
|
+
newStatus: HypothesisStatus;
|
|
30
|
+
}
|
|
31
|
+
export interface Observation {
|
|
32
|
+
source: string;
|
|
33
|
+
type: string;
|
|
34
|
+
value: number;
|
|
35
|
+
timestamp: number;
|
|
36
|
+
metadata?: Record<string, unknown>;
|
|
37
|
+
}
|
|
38
|
+
export declare function runHypothesisMigration(db: Database.Database): void;
|
|
39
|
+
/**
|
|
40
|
+
* Hypothesis Engine: generates and tests hypotheses autonomously.
|
|
41
|
+
*
|
|
42
|
+
* Research approach: The scientific method, automated.
|
|
43
|
+
*
|
|
44
|
+
* 1. OBSERVE: Collect observations from all brains
|
|
45
|
+
* 2. HYPOTHESIZE: Generate hypotheses from patterns in observations
|
|
46
|
+
* - Temporal: "Event A occurs more often during time window X"
|
|
47
|
+
* - Correlation: "When metric A increases, metric B also increases"
|
|
48
|
+
* - Threshold: "Performance degrades when metric A exceeds value X"
|
|
49
|
+
* - Frequency: "Event A happens with period P"
|
|
50
|
+
* 3. TEST: Evaluate hypotheses against historical data using statistical tests
|
|
51
|
+
* 4. CONCLUDE: Accept or reject based on evidence
|
|
52
|
+
*/
|
|
53
|
+
export declare class HypothesisEngine {
|
|
54
|
+
private db;
|
|
55
|
+
private logger;
|
|
56
|
+
private minEvidence;
|
|
57
|
+
private confirmThreshold;
|
|
58
|
+
private rejectThreshold;
|
|
59
|
+
constructor(db: Database.Database, config?: {
|
|
60
|
+
minEvidence?: number;
|
|
61
|
+
confirmThreshold?: number;
|
|
62
|
+
rejectThreshold?: number;
|
|
63
|
+
});
|
|
64
|
+
/** Record an observation for hypothesis generation and testing. */
|
|
65
|
+
observe(observation: Observation): void;
|
|
66
|
+
/** Propose a hypothesis manually or from automated detection. */
|
|
67
|
+
propose(hypothesis: Omit<Hypothesis, 'id' | 'status' | 'evidence_for' | 'evidence_against' | 'confidence' | 'p_value' | 'created_at' | 'tested_at'>): Hypothesis;
|
|
68
|
+
/**
|
|
69
|
+
* Auto-generate hypotheses from observation patterns.
|
|
70
|
+
* This is the creative part — the system forms its own theories.
|
|
71
|
+
*/
|
|
72
|
+
generate(): Hypothesis[];
|
|
73
|
+
/**
|
|
74
|
+
* Test a hypothesis against available data.
|
|
75
|
+
* Returns the test result with updated status.
|
|
76
|
+
*/
|
|
77
|
+
test(hypothesisId: number): HypothesisTestResult | null;
|
|
78
|
+
/** Test all proposed/testing hypotheses. */
|
|
79
|
+
testAll(): HypothesisTestResult[];
|
|
80
|
+
/** Get a hypothesis by ID. */
|
|
81
|
+
get(id: number): Hypothesis | null;
|
|
82
|
+
/** List hypotheses by status. */
|
|
83
|
+
list(status?: HypothesisStatus, limit?: number): Hypothesis[];
|
|
84
|
+
/** Get summary statistics. */
|
|
85
|
+
getSummary(): {
|
|
86
|
+
total: number;
|
|
87
|
+
proposed: number;
|
|
88
|
+
testing: number;
|
|
89
|
+
confirmed: number;
|
|
90
|
+
rejected: number;
|
|
91
|
+
inconclusive: number;
|
|
92
|
+
totalObservations: number;
|
|
93
|
+
topConfirmed: Hypothesis[];
|
|
94
|
+
};
|
|
95
|
+
private generateTemporalHypotheses;
|
|
96
|
+
private generateCorrelationHypotheses;
|
|
97
|
+
private generateThresholdHypotheses;
|
|
98
|
+
private testTemporalHypothesis;
|
|
99
|
+
private testCorrelationHypothesis;
|
|
100
|
+
private testThresholdHypothesis;
|
|
101
|
+
private testFrequencyHypothesis;
|
|
102
|
+
private getObservationTypes;
|
|
103
|
+
private getObservationTimeRange;
|
|
104
|
+
}
|