@timmeck/brain-core 2.36.100 → 2.36.101
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/diagnostics/diagnostic-reports.d.ts +40 -0
- package/dist/diagnostics/diagnostic-reports.js +154 -2
- package/dist/diagnostics/diagnostic-reports.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/research/research-orchestrator.d.ts +5 -0
- package/dist/research/research-orchestrator.js +18 -0
- package/dist/research/research-orchestrator.js.map +1 -1
- package/dist/self-model/experiment-ledger.d.ts +50 -0
- package/dist/self-model/experiment-ledger.js +85 -0
- package/dist/self-model/experiment-ledger.js.map +1 -0
- package/dist/self-model/hypothesis-attribution.d.ts +54 -0
- package/dist/self-model/hypothesis-attribution.js +176 -0
- package/dist/self-model/hypothesis-attribution.js.map +1 -0
- package/dist/self-model/strategy-effectiveness.d.ts +54 -0
- package/dist/self-model/strategy-effectiveness.js +143 -0
- package/dist/self-model/strategy-effectiveness.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Experiment Ledger v1 — Track every significant system change as an experiment.
|
|
3
|
+
*
|
|
4
|
+
* From ChatGPT: "The difference between development and cumulative improvement
|
|
5
|
+
* is whether each change is epistemically justified."
|
|
6
|
+
*
|
|
7
|
+
* Session 142 — Phase D
|
|
8
|
+
*/
|
|
9
|
+
import type Database from 'better-sqlite3';
|
|
10
|
+
export declare function runExperimentLedgerMigration(db: Database.Database): void;
|
|
11
|
+
export interface Experiment {
|
|
12
|
+
experiment_id: string;
|
|
13
|
+
module_owner: string;
|
|
14
|
+
change_description: string;
|
|
15
|
+
linked_report_finding: string | null;
|
|
16
|
+
hypothesis: string;
|
|
17
|
+
baseline_metrics_json: string;
|
|
18
|
+
evaluation_window_hours: number;
|
|
19
|
+
result_metrics_json: string | null;
|
|
20
|
+
side_effects_json: string | null;
|
|
21
|
+
decision: string | null;
|
|
22
|
+
started_at: string;
|
|
23
|
+
evaluated_at: string | null;
|
|
24
|
+
}
|
|
25
|
+
export declare class ExperimentLedgerV2 {
|
|
26
|
+
private db;
|
|
27
|
+
constructor(db: Database.Database);
|
|
28
|
+
/** Start a new experiment. */
|
|
29
|
+
start(params: {
|
|
30
|
+
experimentId: string;
|
|
31
|
+
moduleOwner: string;
|
|
32
|
+
changeDescription: string;
|
|
33
|
+
hypothesis: string;
|
|
34
|
+
baselineMetrics: Record<string, unknown>;
|
|
35
|
+
evaluationWindowHours?: number;
|
|
36
|
+
linkedReportFinding?: string;
|
|
37
|
+
}): Experiment;
|
|
38
|
+
/** Evaluate an experiment with results. */
|
|
39
|
+
evaluate(experimentId: string, params: {
|
|
40
|
+
resultMetrics: Record<string, unknown>;
|
|
41
|
+
sideEffects?: Record<string, unknown>;
|
|
42
|
+
decision: 'keep' | 'revert' | 'needs_more_data';
|
|
43
|
+
}): void;
|
|
44
|
+
/** Get all experiments. */
|
|
45
|
+
list(limit?: number): Experiment[];
|
|
46
|
+
/** Get pending experiments (not yet evaluated). */
|
|
47
|
+
pending(): Experiment[];
|
|
48
|
+
/** Get experiment by ID. */
|
|
49
|
+
get(experimentId: string): Experiment | undefined;
|
|
50
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
const log = getLogger();
|
|
3
|
+
// ── Migration ────────────────────────────────────────
|
|
4
|
+
export function runExperimentLedgerMigration(db) {
|
|
5
|
+
db.exec(`
|
|
6
|
+
CREATE TABLE IF NOT EXISTS experiment_ledger_v2 (
|
|
7
|
+
experiment_id TEXT PRIMARY KEY,
|
|
8
|
+
module_owner TEXT NOT NULL,
|
|
9
|
+
change_description TEXT NOT NULL,
|
|
10
|
+
linked_report_finding TEXT,
|
|
11
|
+
hypothesis TEXT NOT NULL,
|
|
12
|
+
baseline_metrics_json TEXT NOT NULL,
|
|
13
|
+
evaluation_window_hours INTEGER NOT NULL DEFAULT 72,
|
|
14
|
+
result_metrics_json TEXT,
|
|
15
|
+
side_effects_json TEXT,
|
|
16
|
+
decision TEXT,
|
|
17
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
18
|
+
evaluated_at TEXT
|
|
19
|
+
);
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_el_module ON experiment_ledger_v2(module_owner);
|
|
21
|
+
CREATE INDEX IF NOT EXISTS idx_el_decision ON experiment_ledger_v2(decision);
|
|
22
|
+
`);
|
|
23
|
+
}
|
|
24
|
+
// ── Engine ───────────────────────────────────────────
|
|
25
|
+
export class ExperimentLedgerV2 {
|
|
26
|
+
db;
|
|
27
|
+
constructor(db) {
|
|
28
|
+
this.db = db;
|
|
29
|
+
runExperimentLedgerMigration(db);
|
|
30
|
+
}
|
|
31
|
+
/** Start a new experiment. */
|
|
32
|
+
start(params) {
|
|
33
|
+
const experiment = {
|
|
34
|
+
experiment_id: params.experimentId,
|
|
35
|
+
module_owner: params.moduleOwner,
|
|
36
|
+
change_description: params.changeDescription,
|
|
37
|
+
linked_report_finding: params.linkedReportFinding ?? null,
|
|
38
|
+
hypothesis: params.hypothesis,
|
|
39
|
+
baseline_metrics_json: JSON.stringify(params.baselineMetrics),
|
|
40
|
+
evaluation_window_hours: params.evaluationWindowHours ?? 72,
|
|
41
|
+
result_metrics_json: null,
|
|
42
|
+
side_effects_json: null,
|
|
43
|
+
decision: null,
|
|
44
|
+
started_at: new Date().toISOString(),
|
|
45
|
+
evaluated_at: null,
|
|
46
|
+
};
|
|
47
|
+
this.db.prepare(`
|
|
48
|
+
INSERT INTO experiment_ledger_v2 (experiment_id, module_owner, change_description, linked_report_finding, hypothesis, baseline_metrics_json, evaluation_window_hours, started_at)
|
|
49
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
50
|
+
`).run(experiment.experiment_id, experiment.module_owner, experiment.change_description, experiment.linked_report_finding, experiment.hypothesis, experiment.baseline_metrics_json, experiment.evaluation_window_hours, experiment.started_at);
|
|
51
|
+
log.info(`[ledger] Experiment started: ${params.experimentId}`);
|
|
52
|
+
return experiment;
|
|
53
|
+
}
|
|
54
|
+
/** Evaluate an experiment with results. */
|
|
55
|
+
evaluate(experimentId, params) {
|
|
56
|
+
this.db.prepare(`
|
|
57
|
+
UPDATE experiment_ledger_v2 SET
|
|
58
|
+
result_metrics_json = ?,
|
|
59
|
+
side_effects_json = ?,
|
|
60
|
+
decision = ?,
|
|
61
|
+
evaluated_at = datetime('now')
|
|
62
|
+
WHERE experiment_id = ?
|
|
63
|
+
`).run(JSON.stringify(params.resultMetrics), params.sideEffects ? JSON.stringify(params.sideEffects) : null, params.decision, experimentId);
|
|
64
|
+
log.info(`[ledger] Experiment evaluated: ${experimentId} → ${params.decision}`);
|
|
65
|
+
}
|
|
66
|
+
/** Get all experiments. */
|
|
67
|
+
list(limit = 20) {
|
|
68
|
+
return this.db.prepare(`
|
|
69
|
+
SELECT * FROM experiment_ledger_v2 ORDER BY started_at DESC LIMIT ?
|
|
70
|
+
`).all(limit);
|
|
71
|
+
}
|
|
72
|
+
/** Get pending experiments (not yet evaluated). */
|
|
73
|
+
pending() {
|
|
74
|
+
return this.db.prepare(`
|
|
75
|
+
SELECT * FROM experiment_ledger_v2 WHERE decision IS NULL ORDER BY started_at ASC
|
|
76
|
+
`).all();
|
|
77
|
+
}
|
|
78
|
+
/** Get experiment by ID. */
|
|
79
|
+
get(experimentId) {
|
|
80
|
+
return this.db.prepare(`
|
|
81
|
+
SELECT * FROM experiment_ledger_v2 WHERE experiment_id = ?
|
|
82
|
+
`).get(experimentId);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=experiment-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"experiment-ledger.js","sourceRoot":"","sources":["../../src/self-model/experiment-ledger.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAExB,wDAAwD;AAExD,MAAM,UAAU,4BAA4B,CAAC,EAAqB;IAChE,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;GAiBP,CAAC,CAAC;AACL,CAAC;AAmBD,wDAAwD;AAExD,MAAM,OAAO,kBAAkB;IACrB,EAAE,CAAoB;IAE9B,YAAY,EAAqB;QAC/B,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,4BAA4B,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,8BAA8B;IAC9B,KAAK,CAAC,MAQL;QACC,MAAM,UAAU,GAAe;YAC7B,aAAa,EAAE,MAAM,CAAC,YAAY;YAClC,YAAY,EAAE,MAAM,CAAC,WAAW;YAChC,kBAAkB,EAAE,MAAM,CAAC,iBAAiB;YAC5C,qBAAqB,EAAE,MAAM,CAAC,mBAAmB,IAAI,IAAI;YACzD,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,qBAAqB,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC;YAC7D,uBAAuB,EAAE,MAAM,CAAC,qBAAqB,IAAI,EAAE;YAC3D,mBAAmB,EAAE,IAAI;YACzB,iBAAiB,EAAE,IAAI;YACvB,QAAQ,EAAE,IAAI;YACd,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,YAAY,EAAE,IAAI;SACnB,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;KAGf,CAAC,CAAC,GAAG,CACJ,UAAU,CAAC,aAAa,EAAE,UAAU,CAAC,YAAY,EAAE,UAAU,CAAC,kBAAkB,EAChF,UAAU,CAAC,qBAAqB,EAAE,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,qBAAqB,EACzF,UAAU,CAAC,uBAAuB,EAAE,UAAU,CAAC,UAAU,CAC1D,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,gCAAgC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAChE,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,2CAA2C;IAC3C,QAAQ,CAAC,YAAoB,EAAE,MAI9B;QACC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;;KAOf,CAAC,CAAC,GAAG,CACJ,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,EACpC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAC9D,MAAM,CAAC,QAAQ,EACf,YAAY,CACb,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,kCAAkC,YAAY,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,2BAA2B;IAC3B,IAAI,CAAC,KAAK,GAAG,EAAE;QACb,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;KAEtB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAiB,CAAC;IAChC,CAAC;IAED,mDAAmD;IACnD,OAAO;QACL,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;KAEtB,CAAC,CAAC,GAAG,EAAkB,CAAC;IAC3B,CAAC;IAED,4BAA4B;IAC5B,GAAG,CAAC,YAAoB;QACtB,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;KAEtB,CAAC,CAAC,GAAG,CAAC,YAAY,CAA2B,CAAC;IACjD,CAAC;CACF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hypothesis Quality Attribution System — Stage 3 Self-Model
|
|
3
|
+
*
|
|
4
|
+
* Tracks accuracy per generator (source), domain, and type.
|
|
5
|
+
* Enables Brain to evaluate its own thinking tools.
|
|
6
|
+
*
|
|
7
|
+
* Session 142 — Phase A
|
|
8
|
+
*/
|
|
9
|
+
import type Database from 'better-sqlite3';
|
|
10
|
+
export declare function runHypothesisAttributionMigration(db: Database.Database): void;
|
|
11
|
+
export interface HypothesisScore {
|
|
12
|
+
key: string;
|
|
13
|
+
type: string;
|
|
14
|
+
total_resolved: number;
|
|
15
|
+
confirmed: number;
|
|
16
|
+
rejected: number;
|
|
17
|
+
inconclusive: number;
|
|
18
|
+
accuracy: number;
|
|
19
|
+
rejection_rate: number;
|
|
20
|
+
avg_resolution_hours: number | null;
|
|
21
|
+
updated_at: string;
|
|
22
|
+
}
|
|
23
|
+
export interface AttributionReport {
|
|
24
|
+
byGenerator: HypothesisScore[];
|
|
25
|
+
byDomain: HypothesisScore[];
|
|
26
|
+
byType: HypothesisScore[];
|
|
27
|
+
worstGenerators: HypothesisScore[];
|
|
28
|
+
bestGenerators: HypothesisScore[];
|
|
29
|
+
recommendations: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare class HypothesisAttributionEngine {
|
|
32
|
+
private db;
|
|
33
|
+
private log;
|
|
34
|
+
constructor(db: Database.Database);
|
|
35
|
+
/**
|
|
36
|
+
* Rebuild all scores from scratch by scanning hypotheses table.
|
|
37
|
+
* Call periodically (e.g., every 5 cycles).
|
|
38
|
+
*/
|
|
39
|
+
rebuildScores(): {
|
|
40
|
+
generators: number;
|
|
41
|
+
domains: number;
|
|
42
|
+
types: number;
|
|
43
|
+
};
|
|
44
|
+
private upsertScore;
|
|
45
|
+
private computeResolutionTimes;
|
|
46
|
+
/** Get scores for a specific type (generator, domain, hypothesis_type). */
|
|
47
|
+
getScores(type: string): HypothesisScore[];
|
|
48
|
+
/** Get domain accuracy for confidence modulation. */
|
|
49
|
+
getDomainAccuracy(domain: string): number;
|
|
50
|
+
/** Get generator accuracy for throttling decisions. */
|
|
51
|
+
getGeneratorAccuracy(generator: string): number;
|
|
52
|
+
/** Generate full attribution report with recommendations. */
|
|
53
|
+
getReport(): AttributionReport;
|
|
54
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
const log = getLogger();
|
|
3
|
+
// ── Migration ────────────────────────────────────────
|
|
4
|
+
export function runHypothesisAttributionMigration(db) {
|
|
5
|
+
db.exec(`
|
|
6
|
+
CREATE TABLE IF NOT EXISTS hypothesis_scores (
|
|
7
|
+
key TEXT NOT NULL,
|
|
8
|
+
type TEXT NOT NULL,
|
|
9
|
+
total_resolved INTEGER NOT NULL DEFAULT 0,
|
|
10
|
+
confirmed INTEGER NOT NULL DEFAULT 0,
|
|
11
|
+
rejected INTEGER NOT NULL DEFAULT 0,
|
|
12
|
+
inconclusive INTEGER NOT NULL DEFAULT 0,
|
|
13
|
+
accuracy REAL NOT NULL DEFAULT 0,
|
|
14
|
+
rejection_rate REAL NOT NULL DEFAULT 0,
|
|
15
|
+
avg_resolution_hours REAL,
|
|
16
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
17
|
+
PRIMARY KEY (key, type)
|
|
18
|
+
);
|
|
19
|
+
CREATE INDEX IF NOT EXISTS idx_hs_type ON hypothesis_scores(type);
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
22
|
+
// ── Engine ───────────────────────────────────────────
|
|
23
|
+
export class HypothesisAttributionEngine {
|
|
24
|
+
db;
|
|
25
|
+
log = getLogger();
|
|
26
|
+
constructor(db) {
|
|
27
|
+
this.db = db;
|
|
28
|
+
runHypothesisAttributionMigration(db);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Rebuild all scores from scratch by scanning hypotheses table.
|
|
32
|
+
* Call periodically (e.g., every 5 cycles).
|
|
33
|
+
*/
|
|
34
|
+
rebuildScores() {
|
|
35
|
+
let generators = 0;
|
|
36
|
+
let domains = 0;
|
|
37
|
+
let types = 0;
|
|
38
|
+
// Clear existing scores
|
|
39
|
+
this.db.prepare('DELETE FROM hypothesis_scores').run();
|
|
40
|
+
// Score by generator (source column)
|
|
41
|
+
const bySource = this.db.prepare(`
|
|
42
|
+
SELECT source as key,
|
|
43
|
+
count(*) as total,
|
|
44
|
+
sum(case when status = 'confirmed' then 1 else 0 end) as confirmed,
|
|
45
|
+
sum(case when status = 'rejected' then 1 else 0 end) as rejected,
|
|
46
|
+
sum(case when status = 'inconclusive' then 1 else 0 end) as inconclusive
|
|
47
|
+
FROM hypotheses
|
|
48
|
+
WHERE status IN ('confirmed', 'rejected', 'inconclusive')
|
|
49
|
+
GROUP BY source
|
|
50
|
+
`).all();
|
|
51
|
+
for (const row of bySource) {
|
|
52
|
+
this.upsertScore('generator', row);
|
|
53
|
+
generators++;
|
|
54
|
+
}
|
|
55
|
+
// Score by domain
|
|
56
|
+
const byDomain = this.db.prepare(`
|
|
57
|
+
SELECT coalesce(domain, 'general') as key,
|
|
58
|
+
count(*) as total,
|
|
59
|
+
sum(case when status = 'confirmed' then 1 else 0 end) as confirmed,
|
|
60
|
+
sum(case when status = 'rejected' then 1 else 0 end) as rejected,
|
|
61
|
+
sum(case when status = 'inconclusive' then 1 else 0 end) as inconclusive
|
|
62
|
+
FROM hypotheses
|
|
63
|
+
WHERE status IN ('confirmed', 'rejected', 'inconclusive')
|
|
64
|
+
GROUP BY domain
|
|
65
|
+
`).all();
|
|
66
|
+
for (const row of byDomain) {
|
|
67
|
+
this.upsertScore('domain', row);
|
|
68
|
+
domains++;
|
|
69
|
+
}
|
|
70
|
+
// Score by type (correlation, temporal, threshold, etc.)
|
|
71
|
+
const byType = this.db.prepare(`
|
|
72
|
+
SELECT type as key,
|
|
73
|
+
count(*) as total,
|
|
74
|
+
sum(case when status = 'confirmed' then 1 else 0 end) as confirmed,
|
|
75
|
+
sum(case when status = 'rejected' then 1 else 0 end) as rejected,
|
|
76
|
+
sum(case when status = 'inconclusive' then 1 else 0 end) as inconclusive
|
|
77
|
+
FROM hypotheses
|
|
78
|
+
WHERE status IN ('confirmed', 'rejected', 'inconclusive')
|
|
79
|
+
GROUP BY type
|
|
80
|
+
`).all();
|
|
81
|
+
for (const row of byType) {
|
|
82
|
+
this.upsertScore('hypothesis_type', row);
|
|
83
|
+
types++;
|
|
84
|
+
}
|
|
85
|
+
// Also compute avg resolution hours
|
|
86
|
+
this.computeResolutionTimes();
|
|
87
|
+
this.log.info(`[attribution] Rebuilt scores: ${generators} generators, ${domains} domains, ${types} types`);
|
|
88
|
+
return { generators, domains, types };
|
|
89
|
+
}
|
|
90
|
+
upsertScore(type, row) {
|
|
91
|
+
const accuracy = row.total > 0 ? Math.round((row.confirmed / row.total) * 1000) / 1000 : 0;
|
|
92
|
+
const rejectionRate = row.total > 0 ? Math.round((row.rejected / row.total) * 1000) / 1000 : 0;
|
|
93
|
+
this.db.prepare(`
|
|
94
|
+
INSERT INTO hypothesis_scores (key, type, total_resolved, confirmed, rejected, inconclusive, accuracy, rejection_rate, updated_at)
|
|
95
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
96
|
+
ON CONFLICT(key, type) DO UPDATE SET
|
|
97
|
+
total_resolved = excluded.total_resolved,
|
|
98
|
+
confirmed = excluded.confirmed,
|
|
99
|
+
rejected = excluded.rejected,
|
|
100
|
+
inconclusive = excluded.inconclusive,
|
|
101
|
+
accuracy = excluded.accuracy,
|
|
102
|
+
rejection_rate = excluded.rejection_rate,
|
|
103
|
+
updated_at = datetime('now')
|
|
104
|
+
`).run(row.key, type, row.total, row.confirmed, row.rejected, row.inconclusive, accuracy, rejectionRate);
|
|
105
|
+
}
|
|
106
|
+
computeResolutionTimes() {
|
|
107
|
+
// By generator
|
|
108
|
+
const resTimes = this.db.prepare(`
|
|
109
|
+
SELECT source as key, 'generator' as type,
|
|
110
|
+
avg((julianday(tested_at) - julianday(created_at)) * 24) as avg_hours
|
|
111
|
+
FROM hypotheses
|
|
112
|
+
WHERE status IN ('confirmed', 'rejected') AND tested_at IS NOT NULL
|
|
113
|
+
GROUP BY source
|
|
114
|
+
`).all();
|
|
115
|
+
for (const r of resTimes) {
|
|
116
|
+
this.db.prepare(`
|
|
117
|
+
UPDATE hypothesis_scores SET avg_resolution_hours = ? WHERE key = ? AND type = ?
|
|
118
|
+
`).run(Math.round((r.avg_hours ?? 0) * 10) / 10, r.key, r.type);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Get scores for a specific type (generator, domain, hypothesis_type). */
|
|
122
|
+
getScores(type) {
|
|
123
|
+
return this.db.prepare(`
|
|
124
|
+
SELECT * FROM hypothesis_scores WHERE type = ? ORDER BY total_resolved DESC
|
|
125
|
+
`).all(type);
|
|
126
|
+
}
|
|
127
|
+
/** Get domain accuracy for confidence modulation. */
|
|
128
|
+
getDomainAccuracy(domain) {
|
|
129
|
+
const row = this.db.prepare(`
|
|
130
|
+
SELECT accuracy FROM hypothesis_scores WHERE key = ? AND type = 'domain'
|
|
131
|
+
`).get(domain);
|
|
132
|
+
return row?.accuracy ?? 0.5; // default 50% if unknown
|
|
133
|
+
}
|
|
134
|
+
/** Get generator accuracy for throttling decisions. */
|
|
135
|
+
getGeneratorAccuracy(generator) {
|
|
136
|
+
const row = this.db.prepare(`
|
|
137
|
+
SELECT accuracy, total_resolved FROM hypothesis_scores WHERE key = ? AND type = 'generator'
|
|
138
|
+
`).get(generator);
|
|
139
|
+
return row?.accuracy ?? 0.5;
|
|
140
|
+
}
|
|
141
|
+
/** Generate full attribution report with recommendations. */
|
|
142
|
+
getReport() {
|
|
143
|
+
const byGenerator = this.getScores('generator');
|
|
144
|
+
const byDomain = this.getScores('domain');
|
|
145
|
+
const byType = this.getScores('hypothesis_type');
|
|
146
|
+
const worstGenerators = byGenerator
|
|
147
|
+
.filter(g => g.total_resolved >= 30)
|
|
148
|
+
.sort((a, b) => a.accuracy - b.accuracy)
|
|
149
|
+
.slice(0, 3);
|
|
150
|
+
const bestGenerators = byGenerator
|
|
151
|
+
.filter(g => g.total_resolved >= 30)
|
|
152
|
+
.sort((a, b) => b.accuracy - a.accuracy)
|
|
153
|
+
.slice(0, 3);
|
|
154
|
+
const recommendations = [];
|
|
155
|
+
for (const g of worstGenerators) {
|
|
156
|
+
if (g.accuracy < 0.2 && g.total_resolved > 50) {
|
|
157
|
+
recommendations.push(`THROTTLE: Generator "${g.key}" has ${(g.accuracy * 100).toFixed(1)}% accuracy over ${g.total_resolved} hypotheses. Consider reducing its generation rate.`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
for (const d of byDomain) {
|
|
161
|
+
if (d.accuracy < 0.15 && d.total_resolved > 30) {
|
|
162
|
+
recommendations.push(`WEAK DOMAIN: "${d.key}" has ${(d.accuracy * 100).toFixed(1)}% accuracy. Hypotheses in this domain are mostly noise.`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
for (const g of bestGenerators) {
|
|
166
|
+
if (g.accuracy > 0.5 && g.total_resolved > 30) {
|
|
167
|
+
recommendations.push(`STRONG: Generator "${g.key}" has ${(g.accuracy * 100).toFixed(1)}% accuracy. Could benefit from more allocation.`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (recommendations.length === 0) {
|
|
171
|
+
recommendations.push('No strong recommendations yet — need more resolved hypotheses (min 30 per generator).');
|
|
172
|
+
}
|
|
173
|
+
return { byGenerator, byDomain, byType, worstGenerators, bestGenerators, recommendations };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=hypothesis-attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hypothesis-attribution.js","sourceRoot":"","sources":["../../src/self-model/hypothesis-attribution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strategy Effectiveness Tracking — Stage 3 Self-Model
|
|
3
|
+
*
|
|
4
|
+
* Tracks which strategies are actually used, and whether they lead to
|
|
5
|
+
* success or failure. Distinguishes museum strategies from real ones.
|
|
6
|
+
*
|
|
7
|
+
* Session 142 — Phase B
|
|
8
|
+
*/
|
|
9
|
+
import type Database from 'better-sqlite3';
|
|
10
|
+
export declare function runStrategyEffectivenessMigration(db: Database.Database): void;
|
|
11
|
+
export interface StrategyExecution {
|
|
12
|
+
id: string;
|
|
13
|
+
strategy_id: string;
|
|
14
|
+
domain: string | null;
|
|
15
|
+
context_type: string | null;
|
|
16
|
+
target_id: string | null;
|
|
17
|
+
executed_at: string;
|
|
18
|
+
outcome: string;
|
|
19
|
+
outcome_value: number | null;
|
|
20
|
+
notes: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface StrategyHealth {
|
|
23
|
+
id: string;
|
|
24
|
+
domain: string;
|
|
25
|
+
description: string;
|
|
26
|
+
use_count: number;
|
|
27
|
+
success_count: number;
|
|
28
|
+
failure_count: number;
|
|
29
|
+
success_rate: number;
|
|
30
|
+
last_used_at: string | null;
|
|
31
|
+
status: string;
|
|
32
|
+
evidence_count: number;
|
|
33
|
+
}
|
|
34
|
+
export interface StrategyEffectivenessReport {
|
|
35
|
+
totalStrategies: number;
|
|
36
|
+
activeStrategies: number;
|
|
37
|
+
staleStrategies: number;
|
|
38
|
+
totalExecutions: number;
|
|
39
|
+
avgSuccessRate: number;
|
|
40
|
+
strategies: StrategyHealth[];
|
|
41
|
+
unusedStrategies: string[];
|
|
42
|
+
topPerformers: StrategyHealth[];
|
|
43
|
+
recommendations: string[];
|
|
44
|
+
}
|
|
45
|
+
export declare class StrategyEffectivenessEngine {
|
|
46
|
+
private db;
|
|
47
|
+
constructor(db: Database.Database);
|
|
48
|
+
/** Record a strategy execution with outcome. */
|
|
49
|
+
recordExecution(strategyId: string, contextType: string, outcome: 'success' | 'failure' | 'neutral', outcomeValue?: number, targetId?: string, notes?: string): void;
|
|
50
|
+
/** Rebuild use/success counts from executions table. */
|
|
51
|
+
rebuildCounts(): number;
|
|
52
|
+
/** Get full effectiveness report. */
|
|
53
|
+
getReport(): StrategyEffectivenessReport;
|
|
54
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
const log = getLogger();
|
|
3
|
+
// ── Migration ────────────────────────────────────────
|
|
4
|
+
export function runStrategyEffectivenessMigration(db) {
|
|
5
|
+
db.exec(`
|
|
6
|
+
CREATE TABLE IF NOT EXISTS strategy_executions (
|
|
7
|
+
id TEXT PRIMARY KEY,
|
|
8
|
+
strategy_id TEXT NOT NULL,
|
|
9
|
+
domain TEXT,
|
|
10
|
+
context_type TEXT,
|
|
11
|
+
target_id TEXT,
|
|
12
|
+
executed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
13
|
+
outcome TEXT DEFAULT 'pending',
|
|
14
|
+
outcome_value REAL,
|
|
15
|
+
notes TEXT
|
|
16
|
+
);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_se_strategy ON strategy_executions(strategy_id);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_se_outcome ON strategy_executions(outcome);
|
|
19
|
+
`);
|
|
20
|
+
// Add tracking columns to knowledge_strategies if missing
|
|
21
|
+
const cols = db.prepare("PRAGMA table_info(knowledge_strategies)").all();
|
|
22
|
+
const colNames = new Set(cols.map(c => c.name));
|
|
23
|
+
if (!colNames.has('use_count')) {
|
|
24
|
+
try {
|
|
25
|
+
db.exec('ALTER TABLE knowledge_strategies ADD COLUMN use_count INTEGER DEFAULT 0');
|
|
26
|
+
}
|
|
27
|
+
catch { /* exists */ }
|
|
28
|
+
}
|
|
29
|
+
if (!colNames.has('success_count')) {
|
|
30
|
+
try {
|
|
31
|
+
db.exec('ALTER TABLE knowledge_strategies ADD COLUMN success_count INTEGER DEFAULT 0');
|
|
32
|
+
}
|
|
33
|
+
catch { /* exists */ }
|
|
34
|
+
}
|
|
35
|
+
if (!colNames.has('failure_count')) {
|
|
36
|
+
try {
|
|
37
|
+
db.exec('ALTER TABLE knowledge_strategies ADD COLUMN failure_count INTEGER DEFAULT 0');
|
|
38
|
+
}
|
|
39
|
+
catch { /* exists */ }
|
|
40
|
+
}
|
|
41
|
+
if (!colNames.has('last_used_at')) {
|
|
42
|
+
try {
|
|
43
|
+
db.exec('ALTER TABLE knowledge_strategies ADD COLUMN last_used_at TEXT');
|
|
44
|
+
}
|
|
45
|
+
catch { /* exists */ }
|
|
46
|
+
}
|
|
47
|
+
if (!colNames.has('effectiveness')) {
|
|
48
|
+
// May already exist from initial schema
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// ── Engine ───────────────────────────────────────────
|
|
52
|
+
export class StrategyEffectivenessEngine {
|
|
53
|
+
db;
|
|
54
|
+
constructor(db) {
|
|
55
|
+
this.db = db;
|
|
56
|
+
runStrategyEffectivenessMigration(db);
|
|
57
|
+
}
|
|
58
|
+
/** Record a strategy execution with outcome. */
|
|
59
|
+
recordExecution(strategyId, contextType, outcome, outcomeValue, targetId, notes) {
|
|
60
|
+
const id = `exec-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
61
|
+
this.db.prepare(`
|
|
62
|
+
INSERT INTO strategy_executions (id, strategy_id, context_type, target_id, outcome, outcome_value, notes)
|
|
63
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
64
|
+
`).run(id, strategyId, contextType, targetId ?? null, outcome, outcomeValue ?? null, notes ?? null);
|
|
65
|
+
// Update aggregate on knowledge_strategies
|
|
66
|
+
const field = outcome === 'success' ? 'success_count' : outcome === 'failure' ? 'failure_count' : null;
|
|
67
|
+
this.db.prepare(`
|
|
68
|
+
UPDATE knowledge_strategies SET use_count = use_count + 1, last_used_at = datetime('now')
|
|
69
|
+
WHERE id = ?
|
|
70
|
+
`).run(strategyId);
|
|
71
|
+
if (field) {
|
|
72
|
+
this.db.prepare(`
|
|
73
|
+
UPDATE knowledge_strategies SET ${field} = ${field} + 1 WHERE id = ?
|
|
74
|
+
`).run(strategyId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Rebuild use/success counts from executions table. */
|
|
78
|
+
rebuildCounts() {
|
|
79
|
+
const strategies = this.db.prepare('SELECT id FROM knowledge_strategies').all();
|
|
80
|
+
let updated = 0;
|
|
81
|
+
for (const s of strategies) {
|
|
82
|
+
const stats = this.db.prepare(`
|
|
83
|
+
SELECT count(*) as total,
|
|
84
|
+
sum(case when outcome = 'success' then 1 else 0 end) as successes,
|
|
85
|
+
sum(case when outcome = 'failure' then 1 else 0 end) as failures,
|
|
86
|
+
max(executed_at) as last_used
|
|
87
|
+
FROM strategy_executions WHERE strategy_id = ?
|
|
88
|
+
`).get(s.id);
|
|
89
|
+
this.db.prepare(`
|
|
90
|
+
UPDATE knowledge_strategies SET
|
|
91
|
+
use_count = ?, success_count = ?, failure_count = ?, last_used_at = ?
|
|
92
|
+
WHERE id = ?
|
|
93
|
+
`).run(stats.total, stats.successes ?? 0, stats.failures ?? 0, stats.last_used, s.id);
|
|
94
|
+
updated++;
|
|
95
|
+
}
|
|
96
|
+
return updated;
|
|
97
|
+
}
|
|
98
|
+
/** Get full effectiveness report. */
|
|
99
|
+
getReport() {
|
|
100
|
+
const strategies = this.db.prepare(`
|
|
101
|
+
SELECT id, domain, description,
|
|
102
|
+
coalesce(use_count, 0) as use_count,
|
|
103
|
+
coalesce(success_count, 0) as success_count,
|
|
104
|
+
coalesce(failure_count, 0) as failure_count,
|
|
105
|
+
last_used_at,
|
|
106
|
+
coalesce(evidence_count, 0) as evidence_count
|
|
107
|
+
FROM knowledge_strategies ORDER BY use_count DESC
|
|
108
|
+
`).all();
|
|
109
|
+
// Compute success_rate and status
|
|
110
|
+
for (const s of strategies) {
|
|
111
|
+
const total = s.success_count + s.failure_count;
|
|
112
|
+
s.success_rate = total > 0 ? Math.round((s.success_count / total) * 1000) / 10 : 0;
|
|
113
|
+
s.status = s.use_count === 0 ? 'unused' : s.use_count > 0 && !s.last_used_at ? 'stale' : 'active';
|
|
114
|
+
}
|
|
115
|
+
const totalExecutions = this.db.prepare('SELECT count(*) as c FROM strategy_executions').get().c;
|
|
116
|
+
const unusedStrategies = strategies.filter(s => s.use_count === 0).map(s => `${s.id} (${s.domain})`);
|
|
117
|
+
const topPerformers = strategies.filter(s => s.use_count >= 3).sort((a, b) => b.success_rate - a.success_rate).slice(0, 5);
|
|
118
|
+
const recommendations = [];
|
|
119
|
+
if (unusedStrategies.length > strategies.length * 0.5) {
|
|
120
|
+
recommendations.push(`WARNING: ${unusedStrategies.length}/${strategies.length} strategies never used — potential "strategy museum".`);
|
|
121
|
+
}
|
|
122
|
+
for (const s of strategies) {
|
|
123
|
+
if (s.use_count > 10 && s.success_rate < 20) {
|
|
124
|
+
recommendations.push(`WEAK: Strategy "${s.id}" has ${s.success_rate}% success over ${s.use_count} uses. Consider deprecating.`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (totalExecutions === 0) {
|
|
128
|
+
recommendations.push('NO EXECUTIONS recorded yet. Wire recordExecution() into ActionBridge/StrategyForge to start tracking.');
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
totalStrategies: strategies.length,
|
|
132
|
+
activeStrategies: strategies.filter(s => s.status === 'active' || s.use_count > 0).length,
|
|
133
|
+
staleStrategies: strategies.filter(s => s.status === 'unused').length,
|
|
134
|
+
totalExecutions,
|
|
135
|
+
avgSuccessRate: topPerformers.length > 0 ? Math.round(topPerformers.reduce((a, b) => a + b.success_rate, 0) / topPerformers.length * 10) / 10 : 0,
|
|
136
|
+
strategies,
|
|
137
|
+
unusedStrategies,
|
|
138
|
+
topPerformers,
|
|
139
|
+
recommendations,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=strategy-effectiveness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy-effectiveness.js","sourceRoot":"","sources":["../../src/self-model/strategy-effectiveness.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timmeck/brain-core",
|
|
3
|
-
"version": "2.36.
|
|
3
|
+
"version": "2.36.101",
|
|
4
4
|
"description": "Shared core infrastructure for the Brain ecosystem — IPC, MCP, CLI, DB connection, and utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"build": "tsc",
|
|
55
55
|
"dev": "tsx src/index.ts",
|
|
56
56
|
"test": "vitest run",
|
|
57
|
-
"lint": "eslint src/",
|
|
57
|
+
"lint": "eslint src/ --max-warnings 100",
|
|
58
58
|
"lint:fix": "eslint src/ --fix",
|
|
59
59
|
"test:coverage": "vitest --coverage"
|
|
60
60
|
},
|