@timmeck/brain-core 2.5.0 → 2.7.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/dashboard/research-server.d.ts +11 -0
- package/dist/dashboard/research-server.js +47 -0
- package/dist/dashboard/research-server.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/research/adaptive-strategy.d.ts +56 -0
- package/dist/research/adaptive-strategy.js +236 -0
- package/dist/research/adaptive-strategy.js.map +1 -0
- package/dist/research/agenda-engine.d.ts +46 -0
- package/dist/research/agenda-engine.js +264 -0
- package/dist/research/agenda-engine.js.map +1 -0
- package/dist/research/anomaly-detective.d.ts +62 -0
- package/dist/research/anomaly-detective.js +318 -0
- package/dist/research/anomaly-detective.js.map +1 -0
- package/dist/research/counterfactual-engine.d.ts +63 -0
- package/dist/research/counterfactual-engine.js +263 -0
- package/dist/research/counterfactual-engine.js.map +1 -0
- package/dist/research/cross-domain-engine.d.ts +52 -0
- package/dist/research/cross-domain-engine.js +283 -0
- package/dist/research/cross-domain-engine.js.map +1 -0
- package/dist/research/experiment-engine.d.ts +77 -0
- package/dist/research/experiment-engine.js +328 -0
- package/dist/research/experiment-engine.js.map +1 -0
- package/dist/research/journal.d.ts +62 -0
- package/dist/research/journal.js +262 -0
- package/dist/research/journal.js.map +1 -0
- package/dist/research/knowledge-distiller.d.ts +95 -0
- package/dist/research/knowledge-distiller.js +426 -0
- package/dist/research/knowledge-distiller.js.map +1 -0
- package/dist/research/research-orchestrator.d.ts +68 -0
- package/dist/research/research-orchestrator.js +228 -0
- package/dist/research/research-orchestrator.js.map +1 -0
- package/dist/research/self-observer.d.ts +55 -0
- package/dist/research/self-observer.js +268 -0
- package/dist/research/self-observer.js.map +1 -0
- package/package.json +1 -1
- package/research-dashboard.html +735 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
// ── Migration ───────────────────────────────────────────
|
|
3
|
+
export function runExperimentMigration(db) {
|
|
4
|
+
db.exec(`
|
|
5
|
+
CREATE TABLE IF NOT EXISTS experiments (
|
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
name TEXT NOT NULL,
|
|
8
|
+
hypothesis TEXT NOT NULL,
|
|
9
|
+
independent_variable TEXT NOT NULL,
|
|
10
|
+
dependent_variable TEXT NOT NULL,
|
|
11
|
+
control_value REAL NOT NULL,
|
|
12
|
+
treatment_value REAL NOT NULL,
|
|
13
|
+
duration_cycles INTEGER NOT NULL,
|
|
14
|
+
status TEXT NOT NULL DEFAULT 'planned',
|
|
15
|
+
control_results TEXT NOT NULL DEFAULT '[]',
|
|
16
|
+
treatment_results TEXT NOT NULL DEFAULT '[]',
|
|
17
|
+
current_cycle INTEGER NOT NULL DEFAULT 0,
|
|
18
|
+
conclusion TEXT,
|
|
19
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
20
|
+
completed_at TEXT
|
|
21
|
+
);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_experiments_status ON experiments(status);
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
// ── Statistics ──────────────────────────────────────────
|
|
26
|
+
function mean(arr) {
|
|
27
|
+
if (arr.length === 0)
|
|
28
|
+
return 0;
|
|
29
|
+
return arr.reduce((a, b) => a + b, 0) / arr.length;
|
|
30
|
+
}
|
|
31
|
+
function stddev(arr) {
|
|
32
|
+
if (arr.length < 2)
|
|
33
|
+
return 0;
|
|
34
|
+
const m = mean(arr);
|
|
35
|
+
const variance = arr.reduce((sum, x) => sum + (x - m) ** 2, 0) / (arr.length - 1);
|
|
36
|
+
return Math.sqrt(variance);
|
|
37
|
+
}
|
|
38
|
+
/** Welch's t-test for two independent samples with unequal variances. */
|
|
39
|
+
function welchTTest(a, b) {
|
|
40
|
+
const nA = a.length;
|
|
41
|
+
const nB = b.length;
|
|
42
|
+
if (nA < 2 || nB < 2)
|
|
43
|
+
return { t: 0, df: 0, pValue: 1 };
|
|
44
|
+
const meanA = mean(a);
|
|
45
|
+
const meanB = mean(b);
|
|
46
|
+
const varA = stddev(a) ** 2;
|
|
47
|
+
const varB = stddev(b) ** 2;
|
|
48
|
+
const se = Math.sqrt(varA / nA + varB / nB);
|
|
49
|
+
if (se === 0)
|
|
50
|
+
return { t: 0, df: nA + nB - 2, pValue: 1 };
|
|
51
|
+
const t = (meanA - meanB) / se;
|
|
52
|
+
// Welch–Satterthwaite degrees of freedom
|
|
53
|
+
const num = (varA / nA + varB / nB) ** 2;
|
|
54
|
+
const den = (varA / nA) ** 2 / (nA - 1) + (varB / nB) ** 2 / (nB - 1);
|
|
55
|
+
const df = den === 0 ? nA + nB - 2 : num / den;
|
|
56
|
+
// Approximate two-tailed p-value using t-distribution approximation
|
|
57
|
+
const pValue = approxTwoTailedP(Math.abs(t), df);
|
|
58
|
+
return { t, df, pValue };
|
|
59
|
+
}
|
|
60
|
+
/** Approximate two-tailed p-value for t-distribution. Uses normal approximation for large df. */
|
|
61
|
+
function approxTwoTailedP(t, df) {
|
|
62
|
+
if (df <= 0)
|
|
63
|
+
return 1;
|
|
64
|
+
// For large df, t ≈ normal
|
|
65
|
+
if (df > 100) {
|
|
66
|
+
return 2 * normalCDF(-Math.abs(t));
|
|
67
|
+
}
|
|
68
|
+
// Incomplete beta function approximation for Student's t
|
|
69
|
+
const x = df / (df + t * t);
|
|
70
|
+
const a = df / 2;
|
|
71
|
+
const b = 0.5;
|
|
72
|
+
return incompleteBetaApprox(x, a, b);
|
|
73
|
+
}
|
|
74
|
+
/** Standard normal CDF approximation (Abramowitz and Stegun). */
|
|
75
|
+
function normalCDF(x) {
|
|
76
|
+
const a1 = 0.254829592;
|
|
77
|
+
const a2 = -0.284496736;
|
|
78
|
+
const a3 = 1.421413741;
|
|
79
|
+
const a4 = -1.453152027;
|
|
80
|
+
const a5 = 1.061405429;
|
|
81
|
+
const p = 0.3275911;
|
|
82
|
+
const sign = x < 0 ? -1 : 1;
|
|
83
|
+
const absX = Math.abs(x);
|
|
84
|
+
const t = 1.0 / (1.0 + p * absX);
|
|
85
|
+
const y = 1.0 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-absX * absX / 2);
|
|
86
|
+
return 0.5 * (1.0 + sign * y);
|
|
87
|
+
}
|
|
88
|
+
/** Rough approximation of the regularized incomplete beta function. */
|
|
89
|
+
function incompleteBetaApprox(x, a, b) {
|
|
90
|
+
// Use a continued fraction approximation (Lentz's method, simplified)
|
|
91
|
+
if (x <= 0)
|
|
92
|
+
return 0;
|
|
93
|
+
if (x >= 1)
|
|
94
|
+
return 1;
|
|
95
|
+
// For our purposes (t-test p-values), use a simpler approximation
|
|
96
|
+
// Convert to normal approximation: t → z
|
|
97
|
+
const z = Math.sqrt(-2 * Math.log(x)) * Math.sqrt(a);
|
|
98
|
+
return Math.min(1, Math.max(0, 2 * normalCDF(-z)));
|
|
99
|
+
}
|
|
100
|
+
/** Cohen's d effect size. */
|
|
101
|
+
function cohensD(a, b) {
|
|
102
|
+
const pooledStd = Math.sqrt(((a.length - 1) * stddev(a) ** 2 + (b.length - 1) * stddev(b) ** 2) /
|
|
103
|
+
(a.length + b.length - 2));
|
|
104
|
+
if (pooledStd === 0)
|
|
105
|
+
return 0;
|
|
106
|
+
return (mean(a) - mean(b)) / pooledStd;
|
|
107
|
+
}
|
|
108
|
+
/** Minimum sample size for power 0.8, two-tailed. Simplified. */
|
|
109
|
+
function minimumSampleSize(effectSize, alpha = 0.05) {
|
|
110
|
+
if (effectSize <= 0)
|
|
111
|
+
return 100;
|
|
112
|
+
// Approximate: n ≈ 16/d² for power=0.8, alpha=0.05
|
|
113
|
+
const zAlpha = alpha === 0.05 ? 1.96 : 2.576;
|
|
114
|
+
const zBeta = 0.842; // power 0.8
|
|
115
|
+
const n = Math.ceil(2 * ((zAlpha + zBeta) / effectSize) ** 2);
|
|
116
|
+
return Math.max(5, Math.min(n, 1000));
|
|
117
|
+
}
|
|
118
|
+
// ── Engine ──────────────────────────────────────────────
|
|
119
|
+
export class ExperimentEngine {
|
|
120
|
+
db;
|
|
121
|
+
config;
|
|
122
|
+
log = getLogger();
|
|
123
|
+
constructor(db, config) {
|
|
124
|
+
this.db = db;
|
|
125
|
+
this.config = {
|
|
126
|
+
brainName: config.brainName,
|
|
127
|
+
defaultDuration: config.defaultDuration ?? 10,
|
|
128
|
+
alpha: config.alpha ?? 0.05,
|
|
129
|
+
maxConcurrent: config.maxConcurrent ?? 3,
|
|
130
|
+
};
|
|
131
|
+
runExperimentMigration(db);
|
|
132
|
+
}
|
|
133
|
+
/** Propose a new experiment. */
|
|
134
|
+
propose(proposal) {
|
|
135
|
+
const running = this.getRunning().length;
|
|
136
|
+
if (running >= this.config.maxConcurrent) {
|
|
137
|
+
throw new Error(`Maximum ${this.config.maxConcurrent} concurrent experiments. ${running} currently running.`);
|
|
138
|
+
}
|
|
139
|
+
const duration = proposal.duration_cycles ?? this.config.defaultDuration;
|
|
140
|
+
const result = this.db.prepare(`
|
|
141
|
+
INSERT INTO experiments (name, hypothesis, independent_variable, dependent_variable,
|
|
142
|
+
control_value, treatment_value, duration_cycles, status)
|
|
143
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 'planned')
|
|
144
|
+
`).run(proposal.name, proposal.hypothesis, proposal.independent_variable, proposal.dependent_variable, proposal.control_value, proposal.treatment_value, duration);
|
|
145
|
+
return this.get(Number(result.lastInsertRowid));
|
|
146
|
+
}
|
|
147
|
+
/** Start an experiment (transitions from planned to running_control). */
|
|
148
|
+
start(experimentId) {
|
|
149
|
+
const exp = this.get(experimentId);
|
|
150
|
+
if (!exp || exp.status !== 'planned')
|
|
151
|
+
return null;
|
|
152
|
+
this.db.prepare(`UPDATE experiments SET status = 'running_control' WHERE id = ?`).run(experimentId);
|
|
153
|
+
return this.get(experimentId);
|
|
154
|
+
}
|
|
155
|
+
/** Record a measurement for the current phase of an experiment. */
|
|
156
|
+
recordMeasurement(experimentId, value) {
|
|
157
|
+
const exp = this.get(experimentId);
|
|
158
|
+
if (!exp)
|
|
159
|
+
return null;
|
|
160
|
+
if (exp.status === 'running_control') {
|
|
161
|
+
exp.control_results.push(value);
|
|
162
|
+
this.db.prepare(`
|
|
163
|
+
UPDATE experiments SET control_results = ?, current_cycle = ?
|
|
164
|
+
WHERE id = ?
|
|
165
|
+
`).run(JSON.stringify(exp.control_results), exp.current_cycle + 1, experimentId);
|
|
166
|
+
// Check if control phase complete
|
|
167
|
+
if (exp.control_results.length >= exp.duration_cycles) {
|
|
168
|
+
this.db.prepare(`UPDATE experiments SET status = 'running_treatment', current_cycle = 0 WHERE id = ?`).run(experimentId);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else if (exp.status === 'running_treatment') {
|
|
172
|
+
exp.treatment_results.push(value);
|
|
173
|
+
this.db.prepare(`
|
|
174
|
+
UPDATE experiments SET treatment_results = ?, current_cycle = ?
|
|
175
|
+
WHERE id = ?
|
|
176
|
+
`).run(JSON.stringify(exp.treatment_results), exp.current_cycle + 1, experimentId);
|
|
177
|
+
// Check if treatment phase complete
|
|
178
|
+
if (exp.treatment_results.length >= exp.duration_cycles) {
|
|
179
|
+
this.db.prepare(`UPDATE experiments SET status = 'analyzing' WHERE id = ?`).run(experimentId);
|
|
180
|
+
return this.analyze(experimentId);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return this.get(experimentId);
|
|
184
|
+
}
|
|
185
|
+
/** Analyze a completed experiment. */
|
|
186
|
+
analyze(experimentId) {
|
|
187
|
+
const exp = this.get(experimentId);
|
|
188
|
+
if (!exp || (exp.status !== 'analyzing' && exp.status !== 'complete'))
|
|
189
|
+
return null;
|
|
190
|
+
const control = exp.control_results;
|
|
191
|
+
const treatment = exp.treatment_results;
|
|
192
|
+
if (control.length < 2 || treatment.length < 2) {
|
|
193
|
+
const conclusion = {
|
|
194
|
+
significant: false,
|
|
195
|
+
p_value: 1,
|
|
196
|
+
effect_size: 0,
|
|
197
|
+
direction: 'neutral',
|
|
198
|
+
recommendation: 'inconclusive_extend',
|
|
199
|
+
control_mean: mean(control),
|
|
200
|
+
treatment_mean: mean(treatment),
|
|
201
|
+
control_std: stddev(control),
|
|
202
|
+
treatment_std: stddev(treatment),
|
|
203
|
+
};
|
|
204
|
+
this.completeExperiment(experimentId, conclusion);
|
|
205
|
+
return this.get(experimentId);
|
|
206
|
+
}
|
|
207
|
+
// Welch's t-test
|
|
208
|
+
const test = welchTTest(treatment, control);
|
|
209
|
+
// Apply Bonferroni correction if multiple experiments running
|
|
210
|
+
const runningCount = Math.max(1, this.getRunning().length + 1);
|
|
211
|
+
const correctedAlpha = this.config.alpha / runningCount;
|
|
212
|
+
const significant = test.pValue < correctedAlpha;
|
|
213
|
+
// Cohen's d
|
|
214
|
+
const d = cohensD(treatment, control);
|
|
215
|
+
// Direction
|
|
216
|
+
const treatmentMean = mean(treatment);
|
|
217
|
+
const controlMean = mean(control);
|
|
218
|
+
let direction;
|
|
219
|
+
if (!significant)
|
|
220
|
+
direction = 'neutral';
|
|
221
|
+
else if (treatmentMean > controlMean)
|
|
222
|
+
direction = 'positive';
|
|
223
|
+
else
|
|
224
|
+
direction = 'negative';
|
|
225
|
+
// Recommendation
|
|
226
|
+
let recommendation;
|
|
227
|
+
if (!significant) {
|
|
228
|
+
recommendation = 'inconclusive_extend';
|
|
229
|
+
}
|
|
230
|
+
else if (direction === 'positive') {
|
|
231
|
+
recommendation = 'adopt_treatment';
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
recommendation = 'keep_control';
|
|
235
|
+
}
|
|
236
|
+
const conclusion = {
|
|
237
|
+
significant,
|
|
238
|
+
p_value: test.pValue,
|
|
239
|
+
effect_size: Math.abs(d),
|
|
240
|
+
direction,
|
|
241
|
+
recommendation,
|
|
242
|
+
control_mean: controlMean,
|
|
243
|
+
treatment_mean: treatmentMean,
|
|
244
|
+
control_std: stddev(control),
|
|
245
|
+
treatment_std: stddev(treatment),
|
|
246
|
+
};
|
|
247
|
+
this.completeExperiment(experimentId, conclusion);
|
|
248
|
+
return this.get(experimentId);
|
|
249
|
+
}
|
|
250
|
+
/** Abort a running experiment. */
|
|
251
|
+
abort(experimentId) {
|
|
252
|
+
const exp = this.get(experimentId);
|
|
253
|
+
if (!exp || exp.status === 'complete' || exp.status === 'aborted')
|
|
254
|
+
return false;
|
|
255
|
+
this.db.prepare(`
|
|
256
|
+
UPDATE experiments SET status = 'aborted', completed_at = datetime('now') WHERE id = ?
|
|
257
|
+
`).run(experimentId);
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
/** Get a single experiment by ID. */
|
|
261
|
+
get(id) {
|
|
262
|
+
const row = this.db.prepare(`SELECT * FROM experiments WHERE id = ?`).get(id);
|
|
263
|
+
if (!row)
|
|
264
|
+
return null;
|
|
265
|
+
return this.rowToExperiment(row);
|
|
266
|
+
}
|
|
267
|
+
/** List experiments by status. */
|
|
268
|
+
list(status, limit = 20) {
|
|
269
|
+
let sql = `SELECT * FROM experiments`;
|
|
270
|
+
const params = [];
|
|
271
|
+
if (status) {
|
|
272
|
+
sql += ` WHERE status = ?`;
|
|
273
|
+
params.push(status);
|
|
274
|
+
}
|
|
275
|
+
sql += ` ORDER BY CASE status
|
|
276
|
+
WHEN 'running_control' THEN 0
|
|
277
|
+
WHEN 'running_treatment' THEN 1
|
|
278
|
+
WHEN 'analyzing' THEN 2
|
|
279
|
+
WHEN 'planned' THEN 3
|
|
280
|
+
WHEN 'complete' THEN 4
|
|
281
|
+
WHEN 'aborted' THEN 5
|
|
282
|
+
END, id DESC LIMIT ?`;
|
|
283
|
+
params.push(limit);
|
|
284
|
+
return this.db.prepare(sql).all(...params).map(r => this.rowToExperiment(r));
|
|
285
|
+
}
|
|
286
|
+
/** Get currently running experiments. */
|
|
287
|
+
getRunning() {
|
|
288
|
+
return this.db.prepare(`
|
|
289
|
+
SELECT * FROM experiments WHERE status IN ('running_control', 'running_treatment')
|
|
290
|
+
`).all().map(r => this.rowToExperiment(r));
|
|
291
|
+
}
|
|
292
|
+
/** Get results of completed experiments. */
|
|
293
|
+
getResults(limit = 10) {
|
|
294
|
+
return this.db.prepare(`
|
|
295
|
+
SELECT * FROM experiments WHERE status = 'complete' ORDER BY completed_at DESC LIMIT ?
|
|
296
|
+
`).all(limit).map(r => this.rowToExperiment(r));
|
|
297
|
+
}
|
|
298
|
+
/** Calculate minimum required sample size for a desired effect size. */
|
|
299
|
+
getMinimumSampleSize(expectedEffectSize) {
|
|
300
|
+
return minimumSampleSize(expectedEffectSize, this.config.alpha);
|
|
301
|
+
}
|
|
302
|
+
completeExperiment(id, conclusion) {
|
|
303
|
+
this.db.prepare(`
|
|
304
|
+
UPDATE experiments SET status = 'complete', conclusion = ?, completed_at = datetime('now')
|
|
305
|
+
WHERE id = ?
|
|
306
|
+
`).run(JSON.stringify(conclusion), id);
|
|
307
|
+
}
|
|
308
|
+
rowToExperiment(row) {
|
|
309
|
+
return {
|
|
310
|
+
id: row.id,
|
|
311
|
+
name: row.name,
|
|
312
|
+
hypothesis: row.hypothesis,
|
|
313
|
+
independent_variable: row.independent_variable,
|
|
314
|
+
dependent_variable: row.dependent_variable,
|
|
315
|
+
control_value: row.control_value,
|
|
316
|
+
treatment_value: row.treatment_value,
|
|
317
|
+
duration_cycles: row.duration_cycles,
|
|
318
|
+
status: row.status,
|
|
319
|
+
control_results: JSON.parse(row.control_results || '[]'),
|
|
320
|
+
treatment_results: JSON.parse(row.treatment_results || '[]'),
|
|
321
|
+
current_cycle: row.current_cycle,
|
|
322
|
+
conclusion: row.conclusion ? JSON.parse(row.conclusion) : null,
|
|
323
|
+
created_at: row.created_at,
|
|
324
|
+
completed_at: row.completed_at,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=experiment-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment-engine.js","sourceRoot":"","sources":["../../src/research/experiment-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
export type JournalEntryType = 'discovery' | 'experiment' | 'anomaly' | 'adaptation' | 'insight' | 'reflection' | 'milestone';
|
|
3
|
+
export type Significance = 'routine' | 'notable' | 'breakthrough' | 'paradigm_shift';
|
|
4
|
+
export interface JournalEntry {
|
|
5
|
+
id?: number;
|
|
6
|
+
timestamp: number;
|
|
7
|
+
type: JournalEntryType;
|
|
8
|
+
title: string;
|
|
9
|
+
content: string;
|
|
10
|
+
tags: string[];
|
|
11
|
+
references: string[];
|
|
12
|
+
significance: Significance;
|
|
13
|
+
data: Record<string, unknown>;
|
|
14
|
+
created_at?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface JournalSummary {
|
|
17
|
+
total_entries: number;
|
|
18
|
+
by_type: Record<string, number>;
|
|
19
|
+
by_significance: Record<string, number>;
|
|
20
|
+
recent_highlights: JournalEntry[];
|
|
21
|
+
date_range: {
|
|
22
|
+
first: string;
|
|
23
|
+
last: string;
|
|
24
|
+
} | null;
|
|
25
|
+
}
|
|
26
|
+
export interface JournalConfig {
|
|
27
|
+
brainName: string;
|
|
28
|
+
/** Auto-reflect every N cycles. Default: 10 */
|
|
29
|
+
reflectionInterval?: number;
|
|
30
|
+
/** Maximum journal entries before cleanup. Default: 10000 */
|
|
31
|
+
maxEntries?: number;
|
|
32
|
+
}
|
|
33
|
+
export declare function runJournalMigration(db: Database.Database): void;
|
|
34
|
+
export declare class ResearchJournal {
|
|
35
|
+
private db;
|
|
36
|
+
private config;
|
|
37
|
+
private cyclesSinceReflection;
|
|
38
|
+
private log;
|
|
39
|
+
constructor(db: Database.Database, config: JournalConfig);
|
|
40
|
+
/** Write a journal entry. */
|
|
41
|
+
write(entry: Omit<JournalEntry, 'id' | 'timestamp' | 'created_at'>): JournalEntry;
|
|
42
|
+
/** Record a discovery in the journal. */
|
|
43
|
+
recordDiscovery(title: string, description: string, data: Record<string, unknown>, significance?: Significance): JournalEntry;
|
|
44
|
+
/** Record an experiment result. */
|
|
45
|
+
recordExperiment(name: string, result: string, data: Record<string, unknown>, significant: boolean): JournalEntry;
|
|
46
|
+
/** Record an anomaly. */
|
|
47
|
+
recordAnomaly(title: string, description: string, severity: string, data: Record<string, unknown>): JournalEntry;
|
|
48
|
+
/** Record a strategy adaptation. */
|
|
49
|
+
recordAdaptation(parameter: string, oldValue: number, newValue: number, reason: string): JournalEntry;
|
|
50
|
+
/** Generate automatic reflection based on recent entries. */
|
|
51
|
+
reflect(): JournalEntry | null;
|
|
52
|
+
/** Get journal entries, optionally filtered. */
|
|
53
|
+
getEntries(type?: JournalEntryType, limit?: number): JournalEntry[];
|
|
54
|
+
/** Get summary of journal contents. */
|
|
55
|
+
getSummary(limit?: number): JournalSummary;
|
|
56
|
+
/** Get only milestones and breakthroughs. */
|
|
57
|
+
getMilestones(limit?: number): JournalEntry[];
|
|
58
|
+
/** Full-text search across journal entries. */
|
|
59
|
+
search(query: string, limit?: number): JournalEntry[];
|
|
60
|
+
private cleanup;
|
|
61
|
+
private rowToEntry;
|
|
62
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
// ── Migration ───────────────────────────────────────────
|
|
3
|
+
export function runJournalMigration(db) {
|
|
4
|
+
db.exec(`
|
|
5
|
+
CREATE TABLE IF NOT EXISTS research_journal (
|
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
timestamp INTEGER NOT NULL,
|
|
8
|
+
type TEXT NOT NULL,
|
|
9
|
+
title TEXT NOT NULL,
|
|
10
|
+
content TEXT NOT NULL,
|
|
11
|
+
tags TEXT NOT NULL DEFAULT '[]',
|
|
12
|
+
ref_ids TEXT NOT NULL DEFAULT '[]',
|
|
13
|
+
significance TEXT NOT NULL DEFAULT 'routine',
|
|
14
|
+
data TEXT NOT NULL DEFAULT '{}',
|
|
15
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
16
|
+
);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_journal_type ON research_journal(type);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_journal_ts ON research_journal(timestamp);
|
|
19
|
+
CREATE INDEX IF NOT EXISTS idx_journal_sig ON research_journal(significance);
|
|
20
|
+
|
|
21
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS journal_fts USING fts5(
|
|
22
|
+
title, content, tags,
|
|
23
|
+
content='research_journal',
|
|
24
|
+
content_rowid='id'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE TRIGGER IF NOT EXISTS journal_ai AFTER INSERT ON research_journal BEGIN
|
|
28
|
+
INSERT INTO journal_fts(rowid, title, content, tags)
|
|
29
|
+
VALUES (new.id, new.title, new.content, new.tags);
|
|
30
|
+
END;
|
|
31
|
+
CREATE TRIGGER IF NOT EXISTS journal_ad AFTER DELETE ON research_journal BEGIN
|
|
32
|
+
INSERT INTO journal_fts(journal_fts, rowid, title, content, tags)
|
|
33
|
+
VALUES ('delete', old.id, old.title, old.content, old.tags);
|
|
34
|
+
END;
|
|
35
|
+
`);
|
|
36
|
+
}
|
|
37
|
+
// ── Engine ──────────────────────────────────────────────
|
|
38
|
+
export class ResearchJournal {
|
|
39
|
+
db;
|
|
40
|
+
config;
|
|
41
|
+
cyclesSinceReflection = 0;
|
|
42
|
+
log = getLogger();
|
|
43
|
+
constructor(db, config) {
|
|
44
|
+
this.db = db;
|
|
45
|
+
this.config = {
|
|
46
|
+
brainName: config.brainName,
|
|
47
|
+
reflectionInterval: config.reflectionInterval ?? 10,
|
|
48
|
+
maxEntries: config.maxEntries ?? 10_000,
|
|
49
|
+
};
|
|
50
|
+
runJournalMigration(db);
|
|
51
|
+
}
|
|
52
|
+
/** Write a journal entry. */
|
|
53
|
+
write(entry) {
|
|
54
|
+
const timestamp = Date.now();
|
|
55
|
+
const result = this.db.prepare(`
|
|
56
|
+
INSERT INTO research_journal (timestamp, type, title, content, tags, ref_ids, significance, data)
|
|
57
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
58
|
+
`).run(timestamp, entry.type, entry.title, entry.content, JSON.stringify(entry.tags), JSON.stringify(entry.references), entry.significance, JSON.stringify(entry.data));
|
|
59
|
+
this.cleanup();
|
|
60
|
+
return { ...entry, id: Number(result.lastInsertRowid), timestamp };
|
|
61
|
+
}
|
|
62
|
+
/** Record a discovery in the journal. */
|
|
63
|
+
recordDiscovery(title, description, data, significance = 'notable') {
|
|
64
|
+
return this.write({
|
|
65
|
+
type: 'discovery',
|
|
66
|
+
title,
|
|
67
|
+
content: description,
|
|
68
|
+
tags: ['discovery', this.config.brainName],
|
|
69
|
+
references: [],
|
|
70
|
+
significance,
|
|
71
|
+
data,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** Record an experiment result. */
|
|
75
|
+
recordExperiment(name, result, data, significant) {
|
|
76
|
+
return this.write({
|
|
77
|
+
type: 'experiment',
|
|
78
|
+
title: `Experiment: ${name}`,
|
|
79
|
+
content: result,
|
|
80
|
+
tags: ['experiment', significant ? 'significant' : 'not_significant'],
|
|
81
|
+
references: [],
|
|
82
|
+
significance: significant ? 'notable' : 'routine',
|
|
83
|
+
data,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/** Record an anomaly. */
|
|
87
|
+
recordAnomaly(title, description, severity, data) {
|
|
88
|
+
const sig = severity === 'critical' ? 'breakthrough' :
|
|
89
|
+
severity === 'high' ? 'notable' : 'routine';
|
|
90
|
+
return this.write({
|
|
91
|
+
type: 'anomaly',
|
|
92
|
+
title,
|
|
93
|
+
content: description,
|
|
94
|
+
tags: ['anomaly', severity],
|
|
95
|
+
references: [],
|
|
96
|
+
significance: sig,
|
|
97
|
+
data,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/** Record a strategy adaptation. */
|
|
101
|
+
recordAdaptation(parameter, oldValue, newValue, reason) {
|
|
102
|
+
return this.write({
|
|
103
|
+
type: 'adaptation',
|
|
104
|
+
title: `Adapted ${parameter}: ${oldValue.toFixed(3)} → ${newValue.toFixed(3)}`,
|
|
105
|
+
content: reason,
|
|
106
|
+
tags: ['adaptation', parameter],
|
|
107
|
+
references: [],
|
|
108
|
+
significance: 'routine',
|
|
109
|
+
data: { parameter, old_value: oldValue, new_value: newValue },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** Generate automatic reflection based on recent entries. */
|
|
113
|
+
reflect() {
|
|
114
|
+
this.cyclesSinceReflection++;
|
|
115
|
+
if (this.cyclesSinceReflection < this.config.reflectionInterval)
|
|
116
|
+
return null;
|
|
117
|
+
this.cyclesSinceReflection = 0;
|
|
118
|
+
// Get recent entries since last reflection
|
|
119
|
+
const lastReflection = this.db.prepare(`
|
|
120
|
+
SELECT timestamp FROM research_journal WHERE type = 'reflection'
|
|
121
|
+
ORDER BY timestamp DESC LIMIT 1
|
|
122
|
+
`).get();
|
|
123
|
+
const since = lastReflection?.timestamp ?? 0;
|
|
124
|
+
const entries = this.db.prepare(`
|
|
125
|
+
SELECT type, significance, title FROM research_journal
|
|
126
|
+
WHERE timestamp > ? AND type != 'reflection'
|
|
127
|
+
ORDER BY timestamp DESC
|
|
128
|
+
`).all(since);
|
|
129
|
+
if (entries.length === 0)
|
|
130
|
+
return null;
|
|
131
|
+
const byType = new Map();
|
|
132
|
+
const bySignificance = new Map();
|
|
133
|
+
const highlights = [];
|
|
134
|
+
for (const e of entries) {
|
|
135
|
+
byType.set(e.type, (byType.get(e.type) ?? 0) + 1);
|
|
136
|
+
bySignificance.set(e.significance, (bySignificance.get(e.significance) ?? 0) + 1);
|
|
137
|
+
if (e.significance !== 'routine')
|
|
138
|
+
highlights.push(e.title);
|
|
139
|
+
}
|
|
140
|
+
const typeStr = [...byType.entries()].map(([k, v]) => `${v} ${k}(s)`).join(', ');
|
|
141
|
+
const content = [
|
|
142
|
+
`Reflection on ${entries.length} entries since last review:`,
|
|
143
|
+
`Types: ${typeStr}`,
|
|
144
|
+
'',
|
|
145
|
+
];
|
|
146
|
+
if (highlights.length > 0) {
|
|
147
|
+
content.push('Key highlights:');
|
|
148
|
+
for (const h of highlights.slice(0, 5))
|
|
149
|
+
content.push(` - ${h}`);
|
|
150
|
+
content.push('');
|
|
151
|
+
}
|
|
152
|
+
const confirmed = entries.filter(e => e.type === 'experiment' || e.type === 'discovery').length;
|
|
153
|
+
const anomalies = entries.filter(e => e.type === 'anomaly').length;
|
|
154
|
+
if (confirmed > 0)
|
|
155
|
+
content.push(`${confirmed} discoveries/experiments completed.`);
|
|
156
|
+
if (anomalies > 0)
|
|
157
|
+
content.push(`${anomalies} anomalies detected.`);
|
|
158
|
+
return this.write({
|
|
159
|
+
type: 'reflection',
|
|
160
|
+
title: `Reflection: ${entries.length} events reviewed`,
|
|
161
|
+
content: content.join('\n'),
|
|
162
|
+
tags: ['reflection', 'auto'],
|
|
163
|
+
references: [],
|
|
164
|
+
significance: highlights.length >= 3 ? 'notable' : 'routine',
|
|
165
|
+
data: { entries_count: entries.length, by_type: Object.fromEntries(byType), highlights },
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/** Get journal entries, optionally filtered. */
|
|
169
|
+
getEntries(type, limit = 20) {
|
|
170
|
+
let sql = `SELECT * FROM research_journal`;
|
|
171
|
+
const params = [];
|
|
172
|
+
if (type) {
|
|
173
|
+
sql += ` WHERE type = ?`;
|
|
174
|
+
params.push(type);
|
|
175
|
+
}
|
|
176
|
+
sql += ` ORDER BY timestamp DESC LIMIT ?`;
|
|
177
|
+
params.push(limit);
|
|
178
|
+
return this.db.prepare(sql).all(...params).map(r => this.rowToEntry(r));
|
|
179
|
+
}
|
|
180
|
+
/** Get summary of journal contents. */
|
|
181
|
+
getSummary(limit = 5) {
|
|
182
|
+
const total = this.db.prepare(`SELECT COUNT(*) as c FROM research_journal`).get().c;
|
|
183
|
+
const byType = Object.fromEntries(this.db.prepare(`SELECT type, COUNT(*) as c FROM research_journal GROUP BY type`).all()
|
|
184
|
+
.map(r => [r.type, r.c]));
|
|
185
|
+
const bySignificance = Object.fromEntries(this.db.prepare(`SELECT significance, COUNT(*) as c FROM research_journal GROUP BY significance`).all()
|
|
186
|
+
.map(r => [r.significance, r.c]));
|
|
187
|
+
const highlights = this.db.prepare(`
|
|
188
|
+
SELECT * FROM research_journal
|
|
189
|
+
WHERE significance IN ('notable', 'breakthrough', 'paradigm_shift')
|
|
190
|
+
ORDER BY timestamp DESC LIMIT ?
|
|
191
|
+
`).all(limit).map(r => this.rowToEntry(r));
|
|
192
|
+
const dateRange = this.db.prepare(`
|
|
193
|
+
SELECT MIN(created_at) as first, MAX(created_at) as last FROM research_journal
|
|
194
|
+
`).get();
|
|
195
|
+
return {
|
|
196
|
+
total_entries: total,
|
|
197
|
+
by_type: byType,
|
|
198
|
+
by_significance: bySignificance,
|
|
199
|
+
recent_highlights: highlights,
|
|
200
|
+
date_range: dateRange.first ? { first: dateRange.first, last: dateRange.last } : null,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/** Get only milestones and breakthroughs. */
|
|
204
|
+
getMilestones(limit = 10) {
|
|
205
|
+
return this.db.prepare(`
|
|
206
|
+
SELECT * FROM research_journal
|
|
207
|
+
WHERE significance IN ('breakthrough', 'paradigm_shift') OR type = 'milestone'
|
|
208
|
+
ORDER BY timestamp DESC LIMIT ?
|
|
209
|
+
`).all(limit).map(r => this.rowToEntry(r));
|
|
210
|
+
}
|
|
211
|
+
/** Full-text search across journal entries. */
|
|
212
|
+
search(query, limit = 20) {
|
|
213
|
+
try {
|
|
214
|
+
const ids = this.db.prepare(`
|
|
215
|
+
SELECT rowid FROM journal_fts WHERE journal_fts MATCH ? LIMIT ?
|
|
216
|
+
`).all(query, limit);
|
|
217
|
+
if (ids.length === 0)
|
|
218
|
+
return [];
|
|
219
|
+
const placeholders = ids.map(() => '?').join(',');
|
|
220
|
+
return this.db.prepare(`
|
|
221
|
+
SELECT * FROM research_journal WHERE id IN (${placeholders})
|
|
222
|
+
ORDER BY timestamp DESC
|
|
223
|
+
`).all(...ids.map(i => i.rowid)).map(r => this.rowToEntry(r));
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// FTS might fail on invalid query — fallback to LIKE
|
|
227
|
+
return this.db.prepare(`
|
|
228
|
+
SELECT * FROM research_journal
|
|
229
|
+
WHERE title LIKE ? OR content LIKE ?
|
|
230
|
+
ORDER BY timestamp DESC LIMIT ?
|
|
231
|
+
`).all(`%${query}%`, `%${query}%`, limit).map(r => this.rowToEntry(r));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
cleanup() {
|
|
235
|
+
const count = this.db.prepare(`SELECT COUNT(*) as c FROM research_journal`).get().c;
|
|
236
|
+
if (count > this.config.maxEntries) {
|
|
237
|
+
// Keep significant entries, delete old routine ones
|
|
238
|
+
this.db.prepare(`
|
|
239
|
+
DELETE FROM research_journal WHERE id IN (
|
|
240
|
+
SELECT id FROM research_journal
|
|
241
|
+
WHERE significance = 'routine'
|
|
242
|
+
ORDER BY timestamp ASC LIMIT ?
|
|
243
|
+
)
|
|
244
|
+
`).run(count - this.config.maxEntries);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
rowToEntry(row) {
|
|
248
|
+
return {
|
|
249
|
+
id: row.id,
|
|
250
|
+
timestamp: row.timestamp,
|
|
251
|
+
type: row.type,
|
|
252
|
+
title: row.title,
|
|
253
|
+
content: row.content,
|
|
254
|
+
tags: JSON.parse(row.tags || '[]'),
|
|
255
|
+
references: JSON.parse(row.ref_ids || '[]'),
|
|
256
|
+
significance: row.significance,
|
|
257
|
+
data: JSON.parse(row.data || '{}'),
|
|
258
|
+
created_at: row.created_at,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=journal.js.map
|