@timmeck/brain-core 2.36.105 → 2.36.106

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.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Creative Hypothesis Test Paths v1
3
+ *
4
+ * Two primitive, robust test paths for creative/reasoning hypotheses:
5
+ * 1. Co-occurrence test (do entities co-occur in time windows?)
6
+ * 2. IF→THEN chain validation (does condition predict consequence?)
7
+ *
8
+ * Session 142 — Creative Test Paths
9
+ */
10
+ import type Database from 'better-sqlite3';
11
+ export interface CoOccurrenceResult {
12
+ entityA: string;
13
+ entityB: string;
14
+ windowMinutes: number;
15
+ totalWindows: number;
16
+ coOccurrenceWindows: number;
17
+ coOccurrenceRate: number;
18
+ expectedRandomRate: number;
19
+ evidenceFor: number;
20
+ evidenceAgainst: number;
21
+ pValue: number;
22
+ sufficient: boolean;
23
+ }
24
+ export interface IfThenResult {
25
+ condition: string;
26
+ consequence: string;
27
+ totalMatches: number;
28
+ successRate: number;
29
+ evidenceFor: number;
30
+ evidenceAgainst: number;
31
+ sufficient: boolean;
32
+ }
33
+ /**
34
+ * Test whether two entity types co-occur more often than random chance
35
+ * within a given time window.
36
+ */
37
+ export declare function testCoOccurrence(db: Database.Database, entityA: string, entityB: string, windowMinutes?: number, holdoutTimestamp?: number): CoOccurrenceResult;
38
+ /**
39
+ * Test an IF→THEN hypothesis: when condition is met, does consequence follow?
40
+ * Uses observation values (numeric) with simple threshold comparison.
41
+ */
42
+ export declare function testIfThen(db: Database.Database, conditionEntity: string, conditionOperator: '>' | '<' | '=' | '>=' | '<=', conditionValue: number, consequenceEntity: string, consequenceOperator: '>' | '<' | '=' | '>=' | '<=', consequenceValue: number, lagCycles?: number, holdoutTimestamp?: number): IfThenResult;
@@ -0,0 +1,132 @@
1
+ import { getLogger } from '../utils/logger.js';
2
+ const log = getLogger();
3
+ // ── Co-occurrence Test ───────────────────────────────
4
+ /**
5
+ * Test whether two entity types co-occur more often than random chance
6
+ * within a given time window.
7
+ */
8
+ export function testCoOccurrence(db, entityA, entityB, windowMinutes = 10, holdoutTimestamp = 0) {
9
+ const windowMs = windowMinutes * 60 * 1000;
10
+ // Get observations for both entities
11
+ const obsA = db.prepare('SELECT timestamp FROM observations WHERE type = ? AND timestamp > ? ORDER BY timestamp')
12
+ .all(entityA, holdoutTimestamp);
13
+ const obsB = db.prepare('SELECT timestamp FROM observations WHERE type = ? AND timestamp > ? ORDER BY timestamp')
14
+ .all(entityB, holdoutTimestamp);
15
+ if (obsA.length === 0 || obsB.length === 0) {
16
+ return { entityA, entityB, windowMinutes, totalWindows: 0, coOccurrenceWindows: 0, coOccurrenceRate: 0, expectedRandomRate: 0, evidenceFor: 0, evidenceAgainst: 0, pValue: 1, sufficient: false };
17
+ }
18
+ // Bucket into windows
19
+ const allTimestamps = [...obsA.map(o => o.timestamp), ...obsB.map(o => o.timestamp)];
20
+ const minTs = Math.min(...allTimestamps);
21
+ const maxTs = Math.max(...allTimestamps);
22
+ const totalRange = maxTs - minTs;
23
+ if (totalRange <= 0) {
24
+ return { entityA, entityB, windowMinutes, totalWindows: 0, coOccurrenceWindows: 0, coOccurrenceRate: 0, expectedRandomRate: 0, evidenceFor: 0, evidenceAgainst: 0, pValue: 1, sufficient: false };
25
+ }
26
+ // Create windows
27
+ const numWindows = Math.ceil(totalRange / windowMs);
28
+ const setA = new Set();
29
+ const setB = new Set();
30
+ for (const o of obsA)
31
+ setA.add(Math.floor((o.timestamp - minTs) / windowMs));
32
+ for (const o of obsB)
33
+ setB.add(Math.floor((o.timestamp - minTs) / windowMs));
34
+ // Count co-occurrences
35
+ let coOccurrenceWindows = 0;
36
+ let totalActiveWindows = 0;
37
+ for (let i = 0; i < numWindows; i++) {
38
+ const hasA = setA.has(i);
39
+ const hasB = setB.has(i);
40
+ if (hasA || hasB)
41
+ totalActiveWindows++;
42
+ if (hasA && hasB)
43
+ coOccurrenceWindows++;
44
+ }
45
+ const coOccurrenceRate = totalActiveWindows > 0 ? Math.min(1, coOccurrenceWindows / totalActiveWindows) : 0;
46
+ const pA = setA.size / Math.max(numWindows, 1);
47
+ const pB = setB.size / Math.max(numWindows, 1);
48
+ const expectedRandomRate = Math.min(1, pA * pB);
49
+ // Evidence
50
+ const sufficient = totalActiveWindows >= 20;
51
+ let evidenceFor = 0;
52
+ let evidenceAgainst = 0;
53
+ if (sufficient) {
54
+ if (coOccurrenceRate > expectedRandomRate * 1.5) {
55
+ evidenceFor = coOccurrenceWindows;
56
+ evidenceAgainst = Math.max(0, totalActiveWindows - coOccurrenceWindows);
57
+ }
58
+ else if (coOccurrenceRate < expectedRandomRate * 0.7) {
59
+ evidenceAgainst = totalActiveWindows;
60
+ }
61
+ else {
62
+ // Neutral — some evidence both ways
63
+ evidenceFor = coOccurrenceWindows;
64
+ evidenceAgainst = totalActiveWindows - coOccurrenceWindows;
65
+ }
66
+ }
67
+ // Simple p-value approximation
68
+ const z = totalActiveWindows > 0 && expectedRandomRate > 0 && expectedRandomRate < 1
69
+ ? (coOccurrenceRate - expectedRandomRate) / Math.sqrt(expectedRandomRate * (1 - expectedRandomRate) / totalActiveWindows)
70
+ : 0;
71
+ const pValue = Math.min(1, Math.exp(-0.5 * z * z));
72
+ return { entityA, entityB, windowMinutes, totalWindows: totalActiveWindows, coOccurrenceWindows, coOccurrenceRate, expectedRandomRate, evidenceFor, evidenceAgainst, pValue, sufficient };
73
+ }
74
+ // ── IF→THEN Test ─────────────────────────────────────
75
+ /**
76
+ * Test an IF→THEN hypothesis: when condition is met, does consequence follow?
77
+ * Uses observation values (numeric) with simple threshold comparison.
78
+ */
79
+ export function testIfThen(db, conditionEntity, conditionOperator, conditionValue, consequenceEntity, consequenceOperator, consequenceValue, lagCycles = 1, holdoutTimestamp = 0) {
80
+ // Get condition matches
81
+ const opMap = { '>': '>', '<': '<', '=': '=', '>=': '>=', '<=': '<=' };
82
+ const condOp = opMap[conditionOperator] || '>';
83
+ const conditionObs = db.prepare(`
84
+ SELECT timestamp, value FROM observations
85
+ WHERE type = ? AND CAST(value AS REAL) ${condOp} ? AND timestamp > ?
86
+ ORDER BY timestamp
87
+ `).all(conditionEntity, conditionValue, holdoutTimestamp);
88
+ if (conditionObs.length < 10) {
89
+ return { condition: `${conditionEntity} ${conditionOperator} ${conditionValue}`, consequence: `${consequenceEntity} ${consequenceOperator} ${consequenceValue}`, totalMatches: conditionObs.length, successRate: 0, evidenceFor: 0, evidenceAgainst: 0, sufficient: false };
90
+ }
91
+ // For each condition match, check consequence within lag window
92
+ const lagMs = lagCycles * 300_000; // assume ~5min per cycle
93
+ const consOp = opMap[consequenceOperator] || '<';
94
+ let successes = 0;
95
+ for (const cond of conditionObs) {
96
+ const consequenceMatch = db.prepare(`
97
+ SELECT value FROM observations
98
+ WHERE type = ? AND timestamp > ? AND timestamp < ?
99
+ AND CAST(value AS REAL) ${consOp} ?
100
+ LIMIT 1
101
+ `).get(consequenceEntity, cond.timestamp, cond.timestamp + lagMs, consequenceValue);
102
+ if (consequenceMatch)
103
+ successes++;
104
+ }
105
+ const successRate = conditionObs.length > 0 ? successes / conditionObs.length : 0;
106
+ const sufficient = conditionObs.length >= 10;
107
+ let evidenceFor = 0;
108
+ let evidenceAgainst = 0;
109
+ if (sufficient) {
110
+ if (successRate > 0.7) {
111
+ evidenceFor = successes;
112
+ evidenceAgainst = conditionObs.length - successes;
113
+ }
114
+ else if (successRate < 0.3) {
115
+ evidenceAgainst = conditionObs.length;
116
+ }
117
+ else {
118
+ evidenceFor = successes;
119
+ evidenceAgainst = conditionObs.length - successes;
120
+ }
121
+ }
122
+ return {
123
+ condition: `${conditionEntity} ${conditionOperator} ${conditionValue}`,
124
+ consequence: `${consequenceEntity} ${consequenceOperator} ${consequenceValue}`,
125
+ totalMatches: conditionObs.length,
126
+ successRate: Math.round(successRate * 1000) / 1000,
127
+ evidenceFor,
128
+ evidenceAgainst,
129
+ sufficient,
130
+ };
131
+ }
132
+ //# sourceMappingURL=creative-test-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"creative-test-paths.js","sourceRoot":"","sources":["../../src/self-model/creative-test-paths.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AA4BxB,wDAAwD;AAExD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,EAAqB,EACrB,OAAe,EACf,OAAe,EACf,aAAa,GAAG,EAAE,EAClB,gBAAgB,GAAG,CAAC;IAEpB,MAAM,QAAQ,GAAG,aAAa,GAAG,EAAE,GAAG,IAAI,CAAC;IAE3C,qCAAqC;IACrC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,wFAAwF,CAAC;SAC9G,GAAG,CAAC,OAAO,EAAE,gBAAgB,CAAiC,CAAC;IAClE,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,wFAAwF,CAAC;SAC9G,GAAG,CAAC,OAAO,EAAE,gBAAgB,CAAiC,CAAC;IAElE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACpM,CAAC;IAED,sBAAsB;IACtB,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACrF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,CAAC;IAEjC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACpM,CAAC;IAED,iBAAiB;IACjB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IAC7E,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IAE7E,uBAAuB;IACvB,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAC5B,IAAI,kBAAkB,GAAG,CAAC,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,IAAI,IAAI,IAAI;YAAE,kBAAkB,EAAE,CAAC;QACvC,IAAI,IAAI,IAAI,IAAI;YAAE,mBAAmB,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5G,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC/C,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC/C,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAEhD,WAAW;IACX,MAAM,UAAU,GAAG,kBAAkB,IAAI,EAAE,CAAC;IAC5C,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,eAAe,GAAG,CAAC,CAAC;IAExB,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,gBAAgB,GAAG,kBAAkB,GAAG,GAAG,EAAE,CAAC;YAChD,WAAW,GAAG,mBAAmB,CAAC;YAClC,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,GAAG,mBAAmB,CAAC,CAAC;QAC1E,CAAC;aAAM,IAAI,gBAAgB,GAAG,kBAAkB,GAAG,GAAG,EAAE,CAAC;YACvD,eAAe,GAAG,kBAAkB,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,oCAAoC;YACpC,WAAW,GAAG,mBAAmB,CAAC;YAClC,eAAe,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,MAAM,CAAC,GAAG,kBAAkB,GAAG,CAAC,IAAI,kBAAkB,GAAG,CAAC,IAAI,kBAAkB,GAAG,CAAC;QAClF,CAAC,CAAC,CAAC,gBAAgB,GAAG,kBAAkB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC,GAAG,kBAAkB,CAAC,GAAG,kBAAkB,CAAC;QACzH,CAAC,CAAC,CAAC,CAAC;IACN,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAEnD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAC5L,CAAC;AAED,wDAAwD;AAExD;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,EAAqB,EACrB,eAAuB,EACvB,iBAAgD,EAChD,cAAsB,EACtB,iBAAyB,EACzB,mBAAkD,EAClD,gBAAwB,EACxB,SAAS,GAAG,CAAC,EACb,gBAAgB,GAAG,CAAC;IAEpB,wBAAwB;IACxB,MAAM,KAAK,GAA2B,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/F,MAAM,MAAM,GAAG,KAAK,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC;IAE/C,MAAM,YAAY,GAAG,EAAE,CAAC,OAAO,CAAC;;6CAEW,MAAM;;GAEhD,CAAC,CAAC,GAAG,CAAC,eAAe,EAAE,cAAc,EAAE,gBAAgB,CAAgD,CAAC;IAEzG,IAAI,YAAY,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAC7B,OAAO,EAAE,SAAS,EAAE,GAAG,eAAe,IAAI,iBAAiB,IAAI,cAAc,EAAE,EAAE,WAAW,EAAE,GAAG,iBAAiB,IAAI,mBAAmB,IAAI,gBAAgB,EAAE,EAAE,YAAY,EAAE,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAC9Q,CAAC;IAED,gEAAgE;IAChE,MAAM,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC,yBAAyB;IAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,mBAAmB,CAAC,IAAI,GAAG,CAAC;IACjD,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,MAAM,gBAAgB,GAAG,EAAE,CAAC,OAAO,CAAC;;;gCAGR,MAAM;;KAEjC,CAAC,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,GAAG,KAAK,EAAE,gBAAgB,CAAC,CAAC;QAEpF,IAAI,gBAAgB;YAAE,SAAS,EAAE,CAAC;IACpC,CAAC;IAED,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,IAAI,EAAE,CAAC;IAE7C,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,WAAW,GAAG,GAAG,EAAE,CAAC;YACtB,WAAW,GAAG,SAAS,CAAC;YACxB,eAAe,GAAG,YAAY,CAAC,MAAM,GAAG,SAAS,CAAC;QACpD,CAAC;aAAM,IAAI,WAAW,GAAG,GAAG,EAAE,CAAC;YAC7B,eAAe,GAAG,YAAY,CAAC,MAAM,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,WAAW,GAAG,SAAS,CAAC;YACxB,eAAe,GAAG,YAAY,CAAC,MAAM,GAAG,SAAS,CAAC;QACpD,CAAC;IACH,CAAC;IAED,OAAO;QACL,SAAS,EAAE,GAAG,eAAe,IAAI,iBAAiB,IAAI,cAAc,EAAE;QACtE,WAAW,EAAE,GAAG,iBAAiB,IAAI,mBAAmB,IAAI,gBAAgB,EAAE;QAC9E,YAAY,EAAE,YAAY,CAAC,MAAM;QACjC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI;QAClD,WAAW;QACX,eAAe;QACf,UAAU;KACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Generator Self-Improvement Loop v1
3
+ *
4
+ * Automatically adjusts generator constraints based on diagnostics.
5
+ * The system doesn't just DESCRIBE its problems — it CHANGES its behavior.
6
+ *
7
+ * Session 142 — Generator Self-Improvement
8
+ */
9
+ import type Database from 'better-sqlite3';
10
+ export declare function runGeneratorImproverMigration(db: Database.Database): void;
11
+ export interface GeneratorConfig {
12
+ generator_id: string;
13
+ constraints: {
14
+ require_known_entities?: boolean;
15
+ allowed_relations?: string[];
16
+ require_time_window?: boolean;
17
+ };
18
+ mode: 'normal' | 'conservative' | 'restricted';
19
+ weight: number;
20
+ }
21
+ export interface ImprovementAction {
22
+ generatorId: string;
23
+ action: string;
24
+ reason: string;
25
+ oldConfig: GeneratorConfig;
26
+ newConfig: GeneratorConfig;
27
+ }
28
+ export declare class GeneratorImprover {
29
+ private db;
30
+ constructor(db: Database.Database);
31
+ /** Get current config for a generator. */
32
+ getConfig(generatorId: string): GeneratorConfig;
33
+ /** Save config for a generator. */
34
+ private saveConfig;
35
+ /** Log an improvement action. */
36
+ private logAction;
37
+ /**
38
+ * Run the improvement loop — reads diagnostics and adjusts generator configs.
39
+ * Call every 5-10 cycles.
40
+ */
41
+ improve(): ImprovementAction[];
42
+ /** Get improvement history. */
43
+ getHistory(limit?: number): Array<{
44
+ generator_id: string;
45
+ action: string;
46
+ reason: string;
47
+ created_at: string;
48
+ }>;
49
+ /** Get all current configs. */
50
+ getAllConfigs(): GeneratorConfig[];
51
+ }
@@ -0,0 +1,149 @@
1
+ import { getLogger } from '../utils/logger.js';
2
+ const log = getLogger();
3
+ // ── Migration ────────────────────────────────────────
4
+ export function runGeneratorImproverMigration(db) {
5
+ db.exec(`
6
+ CREATE TABLE IF NOT EXISTS generator_config (
7
+ generator_id TEXT PRIMARY KEY,
8
+ constraints_json TEXT NOT NULL DEFAULT '{}',
9
+ mode TEXT NOT NULL DEFAULT 'normal',
10
+ weight REAL NOT NULL DEFAULT 1.0,
11
+ last_updated TEXT NOT NULL DEFAULT (datetime('now'))
12
+ );
13
+
14
+ CREATE TABLE IF NOT EXISTS generator_improvement_log (
15
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
16
+ generator_id TEXT NOT NULL,
17
+ action TEXT NOT NULL,
18
+ reason TEXT NOT NULL,
19
+ old_config_json TEXT,
20
+ new_config_json TEXT,
21
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
22
+ );
23
+ `);
24
+ }
25
+ // ── Engine ───────────────────────────────────────────
26
+ export class GeneratorImprover {
27
+ db;
28
+ constructor(db) {
29
+ this.db = db;
30
+ runGeneratorImproverMigration(db);
31
+ }
32
+ /** Get current config for a generator. */
33
+ getConfig(generatorId) {
34
+ const row = this.db.prepare('SELECT * FROM generator_config WHERE generator_id = ?')
35
+ .get(generatorId);
36
+ if (!row) {
37
+ return { generator_id: generatorId, constraints: {}, mode: 'normal', weight: 1.0 };
38
+ }
39
+ let constraints = {};
40
+ try {
41
+ constraints = JSON.parse(row.constraints_json);
42
+ }
43
+ catch { /* */ }
44
+ return { generator_id: row.generator_id, constraints, mode: row.mode, weight: row.weight };
45
+ }
46
+ /** Save config for a generator. */
47
+ saveConfig(config) {
48
+ this.db.prepare(`
49
+ INSERT INTO generator_config (generator_id, constraints_json, mode, weight, last_updated)
50
+ VALUES (?, ?, ?, ?, datetime('now'))
51
+ ON CONFLICT(generator_id) DO UPDATE SET
52
+ constraints_json = excluded.constraints_json,
53
+ mode = excluded.mode,
54
+ weight = excluded.weight,
55
+ last_updated = datetime('now')
56
+ `).run(config.generator_id, JSON.stringify(config.constraints), config.mode, config.weight);
57
+ }
58
+ /** Log an improvement action. */
59
+ logAction(action) {
60
+ this.db.prepare(`
61
+ INSERT INTO generator_improvement_log (generator_id, action, reason, old_config_json, new_config_json)
62
+ VALUES (?, ?, ?, ?, ?)
63
+ `).run(action.generatorId, action.action, action.reason, JSON.stringify(action.oldConfig), JSON.stringify(action.newConfig));
64
+ }
65
+ /**
66
+ * Run the improvement loop — reads diagnostics and adjusts generator configs.
67
+ * Call every 5-10 cycles.
68
+ */
69
+ improve() {
70
+ const actions = [];
71
+ // Read generator diagnostics
72
+ let diagnostics = [];
73
+ try {
74
+ diagnostics = this.db.prepare('SELECT generator_id, testability_rate, operationalization_rate, validation_rate, total_generated, category FROM generator_diagnostics WHERE total_generated >= 30').all();
75
+ }
76
+ catch {
77
+ return actions;
78
+ }
79
+ for (const diag of diagnostics) {
80
+ const oldConfig = this.getConfig(diag.generator_id);
81
+ const newConfig = { ...oldConfig, constraints: { ...oldConfig.constraints } };
82
+ let action = null;
83
+ let reason = null;
84
+ // Rule 1: Low testability → constrain to known entities
85
+ if (diag.testability_rate < 0.05 && diag.total_generated > 50) {
86
+ if (!oldConfig.constraints.require_known_entities) {
87
+ newConfig.constraints.require_known_entities = true;
88
+ newConfig.constraints.allowed_relations = ['co_occurs', 'correlates', 'if_then'];
89
+ newConfig.constraints.require_time_window = true;
90
+ newConfig.mode = 'restricted';
91
+ action = 'constrain_to_known_entities';
92
+ reason = `testability_rate=${(diag.testability_rate * 100).toFixed(1)}% over ${diag.total_generated} hypotheses — forcing known entities and explicit time windows`;
93
+ }
94
+ }
95
+ // Rule 2: Medium testability + low validation → conservative mode
96
+ if (diag.testability_rate > 0.3 && diag.validation_rate < 0.2 && diag.total_generated > 30) {
97
+ if (oldConfig.mode !== 'conservative') {
98
+ newConfig.mode = 'conservative';
99
+ action = 'set_conservative';
100
+ reason = `testability=${(diag.testability_rate * 100).toFixed(1)}% but validation=${(diag.validation_rate * 100).toFixed(1)}% — reducing novelty`;
101
+ }
102
+ }
103
+ // Rule 3: Strong performer → slight weight boost
104
+ if (diag.validation_rate > 0.5 && diag.testability_rate > 0.5) {
105
+ if (oldConfig.weight < 1.5) {
106
+ newConfig.weight = Math.min(1.5, oldConfig.weight + 0.1);
107
+ action = 'boost_weight';
108
+ reason = `strong performer: validation=${(diag.validation_rate * 100).toFixed(1)}%, testability=${(diag.testability_rate * 100).toFixed(1)}%`;
109
+ }
110
+ }
111
+ // Rule 4: Diversity protection — never fully shut down
112
+ if (newConfig.weight < 0.1) {
113
+ newConfig.weight = 0.1;
114
+ }
115
+ if (action && reason) {
116
+ this.saveConfig(newConfig);
117
+ const improvement = {
118
+ generatorId: diag.generator_id,
119
+ action,
120
+ reason,
121
+ oldConfig,
122
+ newConfig,
123
+ };
124
+ this.logAction(improvement);
125
+ actions.push(improvement);
126
+ log.info(`[improver] ${diag.generator_id}: ${action} — ${reason}`);
127
+ }
128
+ }
129
+ return actions;
130
+ }
131
+ /** Get improvement history. */
132
+ getHistory(limit = 20) {
133
+ return this.db.prepare('SELECT generator_id, action, reason, created_at FROM generator_improvement_log ORDER BY created_at DESC LIMIT ?')
134
+ .all(limit);
135
+ }
136
+ /** Get all current configs. */
137
+ getAllConfigs() {
138
+ const rows = this.db.prepare('SELECT * FROM generator_config').all();
139
+ return rows.map(r => {
140
+ let constraints = {};
141
+ try {
142
+ constraints = JSON.parse(r.constraints_json);
143
+ }
144
+ catch { /* */ }
145
+ return { generator_id: r.generator_id, constraints, mode: r.mode, weight: r.weight };
146
+ });
147
+ }
148
+ }
149
+ //# sourceMappingURL=generator-improver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator-improver.js","sourceRoot":"","sources":["../../src/self-model/generator-improver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * HypothesisOperationalizer — Translates raw creative/reasoning hypotheses
3
+ * into testable operational form.
4
+ *
5
+ * Pipeline: raw hypothesis → entity grounding → relation extraction
6
+ * → temporal normalization → testability scoring → operational hypothesis
7
+ *
8
+ * Session 142 — Testability-Aware Generation v1
9
+ */
10
+ import type Database from 'better-sqlite3';
11
+ export declare function runOperationalizerMigration(db: Database.Database): void;
12
+ export interface OperationalizationResult {
13
+ hypothesisId: number;
14
+ rawStatement: string;
15
+ operationalStatement: string | null;
16
+ entityA: string | null;
17
+ entityB: string | null;
18
+ relationType: 'co_occurs' | 'correlates' | 'if_then' | null;
19
+ windowMinutes: number;
20
+ testabilityScore: number;
21
+ status: 'operationalized' | 'not_yet_operationalized' | 'discarded';
22
+ }
23
+ export interface GeneratorDiagnostic {
24
+ generator_id: string;
25
+ total_generated: number;
26
+ total_operationalized: number;
27
+ total_testable: number;
28
+ total_validated: number;
29
+ confirmed: number;
30
+ rejected: number;
31
+ testability_rate: number;
32
+ operationalization_rate: number;
33
+ validation_rate: number;
34
+ category: string;
35
+ }
36
+ export declare class HypothesisOperationalizer {
37
+ private db;
38
+ private knownEntities;
39
+ constructor(db: Database.Database);
40
+ /** Load all observation types + entity registry as known testable entities. */
41
+ private loadKnownEntities;
42
+ /** Seed entity registry from current observation types. */
43
+ seedEntityRegistry(): number;
44
+ /**
45
+ * Operationalize a single hypothesis.
46
+ * Extracts entities from variables, detects relation type, assigns temporal spec.
47
+ */
48
+ operationalize(hypothesisId: number): OperationalizationResult;
49
+ /**
50
+ * Operationalize all unprocessed creative/reasoning hypotheses.
51
+ */
52
+ operationalizeAll(): {
53
+ processed: number;
54
+ operationalized: number;
55
+ discarded: number;
56
+ notYet: number;
57
+ };
58
+ /**
59
+ * Rebuild generator diagnostics from hypothesis data.
60
+ */
61
+ rebuildDiagnostics(): GeneratorDiagnostic[];
62
+ /** Get generator diagnostics report. */
63
+ getDiagnostics(): GeneratorDiagnostic[];
64
+ }