@mneme-ai/core 2.19.26 → 2.19.27
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/cosmic/aurelian_v1927.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1927.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1927.test.js +73 -0
- package/dist/cosmic/aurelian_v1927.test.js.map +1 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.d.ts +2 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.d.ts.map +1 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.js +153 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.js.map +1 -0
- package/dist/dreamspace_cartographer/index.d.ts +110 -0
- package/dist/dreamspace_cartographer/index.d.ts.map +1 -0
- package/dist/dreamspace_cartographer/index.js +175 -0
- package/dist/dreamspace_cartographer/index.js.map +1 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.d.ts +2 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.d.ts.map +1 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.js +199 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.js.map +1 -0
- package/dist/dreamspace_federate/index.d.ts +131 -0
- package/dist/dreamspace_federate/index.d.ts.map +1 -0
- package/dist/dreamspace_federate/index.js +209 -0
- package/dist/dreamspace_federate/index.js.map +1 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.d.ts +2 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.d.ts.map +1 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.js +175 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.js.map +1 -0
- package/dist/dreamspace_pair/index.d.ts +99 -0
- package/dist/dreamspace_pair/index.d.ts.map +1 -0
- package/dist/dreamspace_pair/index.js +161 -0
- package/dist/dreamspace_pair/index.js.map +1 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.d.ts +2 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.d.ts.map +1 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.js +179 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.js.map +1 -0
- package/dist/dreamspace_probe/index.d.ts +125 -0
- package/dist/dreamspace_probe/index.d.ts.map +1 -0
- package/dist/dreamspace_probe/index.js +226 -0
- package/dist/dreamspace_probe/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/whats_new.d.ts.map +1 -1
- package/dist/whats_new.js +8 -0
- package/dist/whats_new.js.map +1 -1
- package/dist/wrapper_genesis/index.d.ts.map +1 -1
- package/dist/wrapper_genesis/index.js +26 -0
- package/dist/wrapper_genesis/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { scorePair, rankAllPairs, verifyPairReport, formatPairLine, } from "./index.js";
|
|
3
|
+
const SECRET = "pair-test-secret-997744";
|
|
4
|
+
function sample(toolName, result) {
|
|
5
|
+
return { toolName, result };
|
|
6
|
+
}
|
|
7
|
+
function schema(toolName, required, optional = []) {
|
|
8
|
+
return { toolName, requiredProps: required, optionalProps: optional };
|
|
9
|
+
}
|
|
10
|
+
describe("v2.19.27 PAIR · scorePair (mutual info approximation)", () => {
|
|
11
|
+
it("perfect coverage: A's output keys cover ALL of B's required + optional", () => {
|
|
12
|
+
const s = scorePair({
|
|
13
|
+
toolA: "A",
|
|
14
|
+
outputsA: [sample("A", { name: "x", count: 3 })],
|
|
15
|
+
schemaB: schema("B", ["name", "count"], []),
|
|
16
|
+
});
|
|
17
|
+
expect(s.requiredCoverage).toBe(1.0);
|
|
18
|
+
expect(s.optionalCoverage).toBe(1.0);
|
|
19
|
+
expect(s.mutualInfoScore).toBeCloseTo(0.5 + 0.3 + 0.2 * s.keyOverlapScore, 5);
|
|
20
|
+
});
|
|
21
|
+
it("zero coverage: A's keys disjoint from B's required → low MI", () => {
|
|
22
|
+
const s = scorePair({
|
|
23
|
+
toolA: "A",
|
|
24
|
+
outputsA: [sample("A", { foo: 1 })],
|
|
25
|
+
schemaB: schema("B", ["name", "count"]),
|
|
26
|
+
});
|
|
27
|
+
expect(s.requiredCoverage).toBe(0);
|
|
28
|
+
expect(s.mutualInfoScore).toBeLessThan(0.3);
|
|
29
|
+
});
|
|
30
|
+
it("partial required coverage rewards proportionally", () => {
|
|
31
|
+
const s = scorePair({
|
|
32
|
+
toolA: "A",
|
|
33
|
+
outputsA: [sample("A", { name: "x" })],
|
|
34
|
+
schemaB: schema("B", ["name", "count", "ts"]),
|
|
35
|
+
});
|
|
36
|
+
expect(s.requiredCoverage).toBeCloseTo(1 / 3, 5);
|
|
37
|
+
});
|
|
38
|
+
it("case-insensitive key matching", () => {
|
|
39
|
+
const s = scorePair({
|
|
40
|
+
toolA: "A",
|
|
41
|
+
outputsA: [sample("A", { NAME: "x" })],
|
|
42
|
+
schemaB: schema("B", ["name"]),
|
|
43
|
+
});
|
|
44
|
+
expect(s.requiredCoverage).toBe(1.0);
|
|
45
|
+
});
|
|
46
|
+
it("multiple samples union their keys", () => {
|
|
47
|
+
const s = scorePair({
|
|
48
|
+
toolA: "A",
|
|
49
|
+
outputsA: [sample("A", { name: "x" }), sample("A", { count: 1 })],
|
|
50
|
+
schemaB: schema("B", ["name", "count"]),
|
|
51
|
+
});
|
|
52
|
+
expect(s.requiredCoverage).toBe(1.0);
|
|
53
|
+
});
|
|
54
|
+
it("empty required + empty output -> vacuous 1.0 required coverage", () => {
|
|
55
|
+
const s = scorePair({
|
|
56
|
+
toolA: "A",
|
|
57
|
+
outputsA: [sample("A", {})],
|
|
58
|
+
schemaB: schema("B", [], []),
|
|
59
|
+
});
|
|
60
|
+
expect(s.requiredCoverage).toBe(1.0);
|
|
61
|
+
expect(s.optionalCoverage).toBe(1.0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("v2.19.27 PAIR · rankAllPairs (full ordered ranking)", () => {
|
|
65
|
+
it("scores every ordered (A, B) pair; self-pairs excluded", () => {
|
|
66
|
+
const r = rankAllPairs({
|
|
67
|
+
toolOutputs: [
|
|
68
|
+
[sample("A", { name: "x", count: 1 })],
|
|
69
|
+
[sample("B", { name: "y" })],
|
|
70
|
+
],
|
|
71
|
+
toolSchemas: [
|
|
72
|
+
schema("A", ["name"]), // B → A; A → A excluded
|
|
73
|
+
schema("B", ["name"]),
|
|
74
|
+
],
|
|
75
|
+
minScore: 0,
|
|
76
|
+
builtAt: 0,
|
|
77
|
+
secret: SECRET,
|
|
78
|
+
});
|
|
79
|
+
// 2 tools, 2 schemas, no self-pairs -> 2 candidate pairs (A→B, B→A)
|
|
80
|
+
expect(r.totalCandidatePairs).toBe(2);
|
|
81
|
+
});
|
|
82
|
+
it("sorts by mutual info desc; filters below minScore", () => {
|
|
83
|
+
const r = rankAllPairs({
|
|
84
|
+
toolOutputs: [
|
|
85
|
+
[sample("good", { name: "x", count: 1, ts: 1 })],
|
|
86
|
+
[sample("bad", { unrelated: 1 })],
|
|
87
|
+
],
|
|
88
|
+
toolSchemas: [
|
|
89
|
+
schema("good", []),
|
|
90
|
+
schema("bad", []),
|
|
91
|
+
schema("target", ["name", "count", "ts"]),
|
|
92
|
+
],
|
|
93
|
+
minScore: 0.5,
|
|
94
|
+
builtAt: 0,
|
|
95
|
+
secret: SECRET,
|
|
96
|
+
});
|
|
97
|
+
// good → target should rank high; bad → target low (likely filtered)
|
|
98
|
+
expect(r.pairs[0].toolA).toBe("good");
|
|
99
|
+
expect(r.pairs[0].toolB).toBe("target");
|
|
100
|
+
expect(r.pairs.every((p) => p.mutualInfoScore >= 0.5)).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
it("topN respected", () => {
|
|
103
|
+
const r = rankAllPairs({
|
|
104
|
+
toolOutputs: Array.from({ length: 5 }, (_, i) => [sample(`t${i}`, { x: 1 })]),
|
|
105
|
+
toolSchemas: Array.from({ length: 5 }, (_, i) => schema(`t${i}`, ["x"])),
|
|
106
|
+
minScore: 0,
|
|
107
|
+
topN: 3,
|
|
108
|
+
builtAt: 0,
|
|
109
|
+
secret: SECRET,
|
|
110
|
+
});
|
|
111
|
+
expect(r.pairs.length).toBeLessThanOrEqual(3);
|
|
112
|
+
});
|
|
113
|
+
it("HMAC sig verifies; rejects tamper", () => {
|
|
114
|
+
const r = rankAllPairs({
|
|
115
|
+
toolOutputs: [[sample("a", { x: 1 })]],
|
|
116
|
+
toolSchemas: [schema("a", []), schema("b", [])],
|
|
117
|
+
builtAt: 0,
|
|
118
|
+
secret: SECRET,
|
|
119
|
+
});
|
|
120
|
+
expect(verifyPairReport(r, SECRET)).toBe(true);
|
|
121
|
+
expect(verifyPairReport({ ...r, qualifyingPairs: 999 }, SECRET)).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
it("MEASURED 100% determinism: same input -> same sig (30 trials)", () => {
|
|
124
|
+
const input = {
|
|
125
|
+
toolOutputs: [[sample("a", { x: 1 })], [sample("b", { y: 1 })]],
|
|
126
|
+
toolSchemas: [schema("a", ["x"]), schema("b", ["y"])],
|
|
127
|
+
builtAt: 1_000_000,
|
|
128
|
+
secret: SECRET,
|
|
129
|
+
};
|
|
130
|
+
const firstSig = rankAllPairs(input).sig;
|
|
131
|
+
let allEqual = true;
|
|
132
|
+
for (let i = 0; i < 30; i++) {
|
|
133
|
+
if (rankAllPairs(input).sig !== firstSig) {
|
|
134
|
+
allEqual = false;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
expect(allEqual).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
it("MEASURED canonical scenario: truth.forensic→bug_prophet has high MI", () => {
|
|
141
|
+
// truth.forensic outputs { claim, sniffs, verdict, evidence }
|
|
142
|
+
// bug_prophet expects { claim, evidence } as input
|
|
143
|
+
const r = rankAllPairs({
|
|
144
|
+
toolOutputs: [
|
|
145
|
+
[sample("mneme.truth.forensic", { claim: "x", sniffs: [], verdict: "ACCEPTED", evidence: [] })],
|
|
146
|
+
[sample("mneme.bug_prophet", { prophecy: "..." })], // unrelated output
|
|
147
|
+
],
|
|
148
|
+
toolSchemas: [
|
|
149
|
+
schema("mneme.bug_prophet", ["claim", "evidence"]),
|
|
150
|
+
schema("mneme.truth.forensic", ["claim"]),
|
|
151
|
+
],
|
|
152
|
+
minScore: 0.3,
|
|
153
|
+
builtAt: 0,
|
|
154
|
+
secret: SECRET,
|
|
155
|
+
});
|
|
156
|
+
const tfToProphet = r.pairs.find((p) => p.toolA === "mneme.truth.forensic" && p.toolB === "mneme.bug_prophet");
|
|
157
|
+
expect(tfToProphet).toBeDefined();
|
|
158
|
+
expect(tfToProphet.mutualInfoScore).toBeGreaterThanOrEqual(0.5);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
describe("v2.19.27 PAIR · formatter", () => {
|
|
162
|
+
it("formatPairLine includes A → B + MI% + required% + optional%", () => {
|
|
163
|
+
const s = scorePair({
|
|
164
|
+
toolA: "x",
|
|
165
|
+
outputsA: [sample("x", { name: "y" })],
|
|
166
|
+
schemaB: schema("y", ["name"]),
|
|
167
|
+
});
|
|
168
|
+
const line = formatPairLine(s);
|
|
169
|
+
expect(line).toContain("PAIR x → y");
|
|
170
|
+
expect(line).toContain("MI=");
|
|
171
|
+
expect(line).toContain("req=");
|
|
172
|
+
expect(line).toContain("opt=");
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
//# sourceMappingURL=dreamspace_pair.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dreamspace_pair.test.js","sourceRoot":"","sources":["../../src/dreamspace_pair/dreamspace_pair.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.27 — MNEME DREAMSPACE · PAIR (stage 3 of 6)
|
|
3
|
+
*
|
|
4
|
+
* "for every pair (A, B): score = mutual_info(output_A, expected_
|
|
5
|
+
* input_B). top pairs → ผ่านขั้น 4"
|
|
6
|
+
* — user audit, 2026-05-17
|
|
7
|
+
*
|
|
8
|
+
* Diagnosis: v2.19.26 EVOLUTION.selectMatingPairs uses FREQUENCY
|
|
9
|
+
* (how often A→B fires together). PAIR adds QUALITY — measures
|
|
10
|
+
* how well A's output matches what B EXPECTS as input. High
|
|
11
|
+
* mutual_info → A and B are genuinely complementary; safe to splice.
|
|
12
|
+
*
|
|
13
|
+
* We approximate mutual information without LLM: compare key-name
|
|
14
|
+
* overlap (Jaccard over object property names) AND value-type
|
|
15
|
+
* compatibility. Both signals together approximate "would A's output
|
|
16
|
+
* be a plausible input to B?".
|
|
17
|
+
*
|
|
18
|
+
* Composes onto:
|
|
19
|
+
* - v2.19.26 EVOLUTION (replaces co-occurrence ranking with quality)
|
|
20
|
+
* - v2.19.27 PROBE (probe outputs feed PAIR's mutual_info)
|
|
21
|
+
* - v2.19.9 WRAPPER_GENESPLICING (high-mutual-info pairs → chimera)
|
|
22
|
+
* - v2.19.25 SLEEP TRAINING (PAIR fitness blends with jaccard reward)
|
|
23
|
+
*
|
|
24
|
+
* Honest scope:
|
|
25
|
+
* - Mutual info APPROXIMATION via shape-matching, not full Shannon
|
|
26
|
+
* information. Faster, deterministic, sufficient for "are these
|
|
27
|
+
* two tools complementary?" decision.
|
|
28
|
+
* - HMAC-signed PairReport so federation can ship verified pairs.
|
|
29
|
+
*/
|
|
30
|
+
declare const PROTOCOL_VERSION: 1;
|
|
31
|
+
export interface ToolOutputSample {
|
|
32
|
+
toolName: string;
|
|
33
|
+
/** Object output (we focus on object-shape compatibility). */
|
|
34
|
+
result: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
export interface ToolInputSchema {
|
|
37
|
+
toolName: string;
|
|
38
|
+
/** Required + optional property names. */
|
|
39
|
+
requiredProps: string[];
|
|
40
|
+
optionalProps: string[];
|
|
41
|
+
}
|
|
42
|
+
export interface PairScore {
|
|
43
|
+
toolA: string;
|
|
44
|
+
toolB: string;
|
|
45
|
+
/** Object key overlap A.outputs vs B.requiredProps (Jaccard 0..1). */
|
|
46
|
+
keyOverlapScore: number;
|
|
47
|
+
/** Required-coverage: fraction of B's required props that A produces. */
|
|
48
|
+
requiredCoverage: number;
|
|
49
|
+
/** Optional-coverage: fraction of B's optional props A also produces. */
|
|
50
|
+
optionalCoverage: number;
|
|
51
|
+
/** Final mutual_info approximation (weighted blend). */
|
|
52
|
+
mutualInfoScore: number;
|
|
53
|
+
}
|
|
54
|
+
export interface PairReport {
|
|
55
|
+
v: typeof PROTOCOL_VERSION;
|
|
56
|
+
pairs: PairScore[];
|
|
57
|
+
totalCandidatePairs: number;
|
|
58
|
+
qualifyingPairs: number;
|
|
59
|
+
minScore: number;
|
|
60
|
+
builtAt: number;
|
|
61
|
+
sig: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Score a single (A, B) pair: how complementary is A's output to B's
|
|
65
|
+
* expected input?
|
|
66
|
+
*
|
|
67
|
+
* keyOverlapScore = jaccard(unionOutputKeys(A), requiredProps(B) ∪ optionalProps(B))
|
|
68
|
+
* requiredCoverage = |outputKeys(A) ∩ requiredProps(B)| / |requiredProps(B)|
|
|
69
|
+
* optionalCoverage = |outputKeys(A) ∩ optionalProps(B)| / |optionalProps(B)|
|
|
70
|
+
* mutualInfoScore = 0.5 * requiredCoverage + 0.3 * optionalCoverage + 0.2 * keyOverlapScore
|
|
71
|
+
*
|
|
72
|
+
* Required-coverage dominates because B will THROW if a required prop
|
|
73
|
+
* is missing; optional is nice-to-have; raw key overlap captures broader
|
|
74
|
+
* signal compatibility.
|
|
75
|
+
*/
|
|
76
|
+
export declare function scorePair(input: {
|
|
77
|
+
toolA: string;
|
|
78
|
+
outputsA: ToolOutputSample[];
|
|
79
|
+
schemaB: ToolInputSchema;
|
|
80
|
+
}): PairScore;
|
|
81
|
+
/**
|
|
82
|
+
* Score ALL ordered (A, B) pairs across the supplied tools; filter
|
|
83
|
+
* above minScore; sort by mutualInfoScore desc. Self-pairs excluded.
|
|
84
|
+
*
|
|
85
|
+
* Returns top pairs ready to feed into v2.19.26 GESTATION as
|
|
86
|
+
* `pattern_co_occurrence` signals with quality (not just frequency).
|
|
87
|
+
*/
|
|
88
|
+
export declare function rankAllPairs(input: {
|
|
89
|
+
toolOutputs: ToolOutputSample[][];
|
|
90
|
+
toolSchemas: ToolInputSchema[];
|
|
91
|
+
minScore?: number;
|
|
92
|
+
topN?: number;
|
|
93
|
+
builtAt?: number;
|
|
94
|
+
secret?: string;
|
|
95
|
+
}): PairReport;
|
|
96
|
+
export declare function verifyPairReport(r: PairReport, secret?: string): boolean;
|
|
97
|
+
export declare function formatPairLine(p: PairScore): string;
|
|
98
|
+
export {};
|
|
99
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dreamspace_pair/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,QAAA,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAGpC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,OAAO,gBAAgB,CAAC;IAC3B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AA0CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,OAAO,EAAE,eAAe,CAAC;CAC1B,GAAG,SAAS,CAkBZ;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,WAAW,EAAE,gBAAgB,EAAE,EAAE,CAAC;IAClC,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,UAAU,CAgCb;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAGxE;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAGnD"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.27 — MNEME DREAMSPACE · PAIR (stage 3 of 6)
|
|
3
|
+
*
|
|
4
|
+
* "for every pair (A, B): score = mutual_info(output_A, expected_
|
|
5
|
+
* input_B). top pairs → ผ่านขั้น 4"
|
|
6
|
+
* — user audit, 2026-05-17
|
|
7
|
+
*
|
|
8
|
+
* Diagnosis: v2.19.26 EVOLUTION.selectMatingPairs uses FREQUENCY
|
|
9
|
+
* (how often A→B fires together). PAIR adds QUALITY — measures
|
|
10
|
+
* how well A's output matches what B EXPECTS as input. High
|
|
11
|
+
* mutual_info → A and B are genuinely complementary; safe to splice.
|
|
12
|
+
*
|
|
13
|
+
* We approximate mutual information without LLM: compare key-name
|
|
14
|
+
* overlap (Jaccard over object property names) AND value-type
|
|
15
|
+
* compatibility. Both signals together approximate "would A's output
|
|
16
|
+
* be a plausible input to B?".
|
|
17
|
+
*
|
|
18
|
+
* Composes onto:
|
|
19
|
+
* - v2.19.26 EVOLUTION (replaces co-occurrence ranking with quality)
|
|
20
|
+
* - v2.19.27 PROBE (probe outputs feed PAIR's mutual_info)
|
|
21
|
+
* - v2.19.9 WRAPPER_GENESPLICING (high-mutual-info pairs → chimera)
|
|
22
|
+
* - v2.19.25 SLEEP TRAINING (PAIR fitness blends with jaccard reward)
|
|
23
|
+
*
|
|
24
|
+
* Honest scope:
|
|
25
|
+
* - Mutual info APPROXIMATION via shape-matching, not full Shannon
|
|
26
|
+
* information. Faster, deterministic, sufficient for "are these
|
|
27
|
+
* two tools complementary?" decision.
|
|
28
|
+
* - HMAC-signed PairReport so federation can ship verified pairs.
|
|
29
|
+
*/
|
|
30
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
31
|
+
const PROTOCOL_VERSION = 1;
|
|
32
|
+
const DEFAULT_MIN_SCORE = 0.3;
|
|
33
|
+
function canon(v) {
|
|
34
|
+
if (v === null || typeof v !== "object")
|
|
35
|
+
return JSON.stringify(v);
|
|
36
|
+
if (Array.isArray(v))
|
|
37
|
+
return "[" + v.map(canon).join(",") + "]";
|
|
38
|
+
const keys = Object.keys(v).sort();
|
|
39
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
|
|
40
|
+
}
|
|
41
|
+
function defaultSecret() {
|
|
42
|
+
return process.env["MNEME_DREAMSPACE_PAIR_SECRET"] || `mneme-dreamspace-pair-v${PROTOCOL_VERSION}`;
|
|
43
|
+
}
|
|
44
|
+
function hmacHex(body, secret) {
|
|
45
|
+
return createHmac("sha256", secret).update(canon(body)).digest("hex");
|
|
46
|
+
}
|
|
47
|
+
function safeEqHex(a, b) {
|
|
48
|
+
try {
|
|
49
|
+
return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Jaccard over two string sets, case-insensitive. */
|
|
56
|
+
function jaccardKeys(a, b) {
|
|
57
|
+
const sa = new Set(a.map((x) => x.toLowerCase()));
|
|
58
|
+
const sb = new Set(b.map((x) => x.toLowerCase()));
|
|
59
|
+
if (sa.size === 0 && sb.size === 0)
|
|
60
|
+
return 1.0;
|
|
61
|
+
if (sa.size === 0 || sb.size === 0)
|
|
62
|
+
return 0.0;
|
|
63
|
+
let inter = 0;
|
|
64
|
+
for (const x of sa)
|
|
65
|
+
if (sb.has(x))
|
|
66
|
+
inter++;
|
|
67
|
+
return inter / (sa.size + sb.size - inter);
|
|
68
|
+
}
|
|
69
|
+
/** Union of all output keys observed across the tool's samples. */
|
|
70
|
+
function unionOutputKeys(samples) {
|
|
71
|
+
const keys = new Set();
|
|
72
|
+
for (const s of samples) {
|
|
73
|
+
for (const k of Object.keys(s.result))
|
|
74
|
+
keys.add(k.toLowerCase());
|
|
75
|
+
}
|
|
76
|
+
return Array.from(keys).sort();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Score a single (A, B) pair: how complementary is A's output to B's
|
|
80
|
+
* expected input?
|
|
81
|
+
*
|
|
82
|
+
* keyOverlapScore = jaccard(unionOutputKeys(A), requiredProps(B) ∪ optionalProps(B))
|
|
83
|
+
* requiredCoverage = |outputKeys(A) ∩ requiredProps(B)| / |requiredProps(B)|
|
|
84
|
+
* optionalCoverage = |outputKeys(A) ∩ optionalProps(B)| / |optionalProps(B)|
|
|
85
|
+
* mutualInfoScore = 0.5 * requiredCoverage + 0.3 * optionalCoverage + 0.2 * keyOverlapScore
|
|
86
|
+
*
|
|
87
|
+
* Required-coverage dominates because B will THROW if a required prop
|
|
88
|
+
* is missing; optional is nice-to-have; raw key overlap captures broader
|
|
89
|
+
* signal compatibility.
|
|
90
|
+
*/
|
|
91
|
+
export function scorePair(input) {
|
|
92
|
+
const outputKeysA = unionOutputKeys(input.outputsA);
|
|
93
|
+
const setA = new Set(outputKeysA);
|
|
94
|
+
const reqB = input.schemaB.requiredProps.map((p) => p.toLowerCase());
|
|
95
|
+
const optB = input.schemaB.optionalProps.map((p) => p.toLowerCase());
|
|
96
|
+
const allB = [...reqB, ...optB];
|
|
97
|
+
const keyOverlap = jaccardKeys(outputKeysA, allB);
|
|
98
|
+
const reqCov = reqB.length === 0 ? 1.0 : reqB.filter((k) => setA.has(k)).length / reqB.length;
|
|
99
|
+
const optCov = optB.length === 0 ? 1.0 : optB.filter((k) => setA.has(k)).length / optB.length;
|
|
100
|
+
const mi = 0.5 * reqCov + 0.3 * optCov + 0.2 * keyOverlap;
|
|
101
|
+
return {
|
|
102
|
+
toolA: input.toolA,
|
|
103
|
+
toolB: input.schemaB.toolName,
|
|
104
|
+
keyOverlapScore: keyOverlap,
|
|
105
|
+
requiredCoverage: reqCov,
|
|
106
|
+
optionalCoverage: optCov,
|
|
107
|
+
mutualInfoScore: mi,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Score ALL ordered (A, B) pairs across the supplied tools; filter
|
|
112
|
+
* above minScore; sort by mutualInfoScore desc. Self-pairs excluded.
|
|
113
|
+
*
|
|
114
|
+
* Returns top pairs ready to feed into v2.19.26 GESTATION as
|
|
115
|
+
* `pattern_co_occurrence` signals with quality (not just frequency).
|
|
116
|
+
*/
|
|
117
|
+
export function rankAllPairs(input) {
|
|
118
|
+
const minScore = input.minScore ?? DEFAULT_MIN_SCORE;
|
|
119
|
+
const topN = input.topN ?? 25;
|
|
120
|
+
const samplesByTool = new Map();
|
|
121
|
+
for (const arr of input.toolOutputs) {
|
|
122
|
+
if (arr.length === 0)
|
|
123
|
+
continue;
|
|
124
|
+
const name = arr[0].toolName;
|
|
125
|
+
const prev = samplesByTool.get(name) ?? [];
|
|
126
|
+
samplesByTool.set(name, prev.concat(arr));
|
|
127
|
+
}
|
|
128
|
+
const scoredPairs = [];
|
|
129
|
+
let totalCandidatePairs = 0;
|
|
130
|
+
for (const [aName, aSamples] of samplesByTool) {
|
|
131
|
+
for (const schemaB of input.toolSchemas) {
|
|
132
|
+
if (aName === schemaB.toolName)
|
|
133
|
+
continue;
|
|
134
|
+
totalCandidatePairs++;
|
|
135
|
+
const s = scorePair({ toolA: aName, outputsA: aSamples, schemaB });
|
|
136
|
+
if (s.mutualInfoScore >= minScore)
|
|
137
|
+
scoredPairs.push(s);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
scoredPairs.sort((a, b) => b.mutualInfoScore - a.mutualInfoScore || a.toolA.localeCompare(b.toolA) || a.toolB.localeCompare(b.toolB));
|
|
141
|
+
const top = scoredPairs.slice(0, topN);
|
|
142
|
+
const body = {
|
|
143
|
+
v: PROTOCOL_VERSION,
|
|
144
|
+
pairs: top,
|
|
145
|
+
totalCandidatePairs,
|
|
146
|
+
qualifyingPairs: scoredPairs.length,
|
|
147
|
+
minScore,
|
|
148
|
+
builtAt: input.builtAt ?? Date.now(),
|
|
149
|
+
};
|
|
150
|
+
const sig = hmacHex(body, input.secret ?? defaultSecret());
|
|
151
|
+
return { ...body, sig };
|
|
152
|
+
}
|
|
153
|
+
export function verifyPairReport(r, secret) {
|
|
154
|
+
const { sig, ...body } = r;
|
|
155
|
+
return safeEqHex(hmacHex(body, secret ?? defaultSecret()), sig);
|
|
156
|
+
}
|
|
157
|
+
export function formatPairLine(p) {
|
|
158
|
+
const mi = (p.mutualInfoScore * 100).toFixed(0);
|
|
159
|
+
return `💞 PAIR ${p.toolA} → ${p.toolB} · MI=${mi}% · req=${(p.requiredCoverage * 100).toFixed(0)}% · opt=${(p.optionalCoverage * 100).toFixed(0)}%`;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dreamspace_pair/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dreamspace_probe.test.d.ts","sourceRoot":"","sources":["../../src/dreamspace_probe/dreamspace_probe.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { latencyScore, outputShapeEntropy, errorRate, utilityScore, aggregateFitness, finaliseProbe, runProbeBattery, verifyProbeReport, formatProbeLine, } from "./index.js";
|
|
3
|
+
const SECRET = "probe-test-secret-997744";
|
|
4
|
+
function run(opts = {}) {
|
|
5
|
+
return {
|
|
6
|
+
inputLabel: "x",
|
|
7
|
+
inputSource: "synthetic",
|
|
8
|
+
latencyMs: 10,
|
|
9
|
+
ok: true,
|
|
10
|
+
result: { ok: true },
|
|
11
|
+
...opts,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
describe("v2.19.27 PROBE · latencyScore", () => {
|
|
15
|
+
it("1.0 when within budget (100ms default)", () => {
|
|
16
|
+
expect(latencyScore(50)).toBe(1.0);
|
|
17
|
+
expect(latencyScore(100)).toBe(1.0);
|
|
18
|
+
});
|
|
19
|
+
it("exponential decay past budget (half at +200ms)", () => {
|
|
20
|
+
expect(latencyScore(300)).toBeCloseTo(0.5, 5);
|
|
21
|
+
expect(latencyScore(500)).toBeCloseTo(0.25, 5);
|
|
22
|
+
});
|
|
23
|
+
it("custom budget + half-life respected", () => {
|
|
24
|
+
expect(latencyScore(50, 30, 20)).toBeCloseTo(Math.pow(0.5, (50 - 30) / 20), 5);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe("v2.19.27 PROBE · outputShapeEntropy", () => {
|
|
28
|
+
it("empty results -> 0", () => {
|
|
29
|
+
expect(outputShapeEntropy([])).toBe(0);
|
|
30
|
+
});
|
|
31
|
+
it("identical shapes -> 0 entropy (flat output)", () => {
|
|
32
|
+
expect(outputShapeEntropy([{ a: 1 }, { a: 2 }, { a: 3 }])).toBe(0);
|
|
33
|
+
});
|
|
34
|
+
it("diverse shapes -> high entropy", () => {
|
|
35
|
+
const ent = outputShapeEntropy([
|
|
36
|
+
{ a: 1 }, { b: 1 }, [1, 2, 3], "string", 42, null,
|
|
37
|
+
]);
|
|
38
|
+
expect(ent).toBeGreaterThan(0.5);
|
|
39
|
+
});
|
|
40
|
+
it("array length buckets distinguish small/med/large", () => {
|
|
41
|
+
const e = outputShapeEntropy([[], [1, 2], new Array(20).fill(0), new Array(200).fill(0)]);
|
|
42
|
+
expect(e).toBeGreaterThan(0.5);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("v2.19.27 PROBE · errorRate", () => {
|
|
46
|
+
it("zero runs -> 0", () => {
|
|
47
|
+
expect(errorRate([])).toBe(0);
|
|
48
|
+
});
|
|
49
|
+
it("all errors -> 1.0", () => {
|
|
50
|
+
expect(errorRate([run({ ok: false }), run({ ok: false })])).toBe(1.0);
|
|
51
|
+
});
|
|
52
|
+
it("half errors -> 0.5", () => {
|
|
53
|
+
expect(errorRate([run({ ok: true }), run({ ok: false })])).toBe(0.5);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe("v2.19.27 PROBE · utilityScore", () => {
|
|
57
|
+
it("all useful results -> 1.0", () => {
|
|
58
|
+
expect(utilityScore([run({ result: { x: 1 } }), run({ result: "hello" })])).toBe(1.0);
|
|
59
|
+
});
|
|
60
|
+
it("empty / null / undefined treated as useless", () => {
|
|
61
|
+
expect(utilityScore([
|
|
62
|
+
run({ result: null }), run({ result: undefined }),
|
|
63
|
+
run({ result: "" }), run({ result: [] }), run({ result: {} }),
|
|
64
|
+
])).toBe(0);
|
|
65
|
+
});
|
|
66
|
+
it("errored runs don't count as useful", () => {
|
|
67
|
+
expect(utilityScore([run({ ok: false }), run({ ok: true, result: { x: 1 } })])).toBe(0.5);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("v2.19.27 PROBE · aggregateFitness (geometric mean of 4 scores)", () => {
|
|
71
|
+
it("all perfect -> 1.0", () => {
|
|
72
|
+
expect(aggregateFitness({ latencyScore: 1, outputEntropy: 1, errorRate: 0, utilityScore: 1 })).toBeCloseTo(1, 5);
|
|
73
|
+
});
|
|
74
|
+
it("any zero (or near-zero) drags geometric mean toward floor", () => {
|
|
75
|
+
const f = aggregateFitness({ latencyScore: 1, outputEntropy: 1, errorRate: 1, utilityScore: 1 });
|
|
76
|
+
expect(f).toBeLessThan(0.1);
|
|
77
|
+
});
|
|
78
|
+
it("balanced mid -> ~0.5", () => {
|
|
79
|
+
const f = aggregateFitness({ latencyScore: 0.5, outputEntropy: 0.5, errorRate: 0.5, utilityScore: 0.5 });
|
|
80
|
+
expect(f).toBeCloseTo(0.5, 1);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe("v2.19.27 PROBE · finaliseProbe (pure aggregator)", () => {
|
|
84
|
+
it("produces HMAC-signed report with all 4 metrics + fitness", () => {
|
|
85
|
+
const r = finaliseProbe({
|
|
86
|
+
toolName: "mneme.x",
|
|
87
|
+
runs: [run({ latencyMs: 50, result: { a: 1 } }), run({ latencyMs: 70, result: { b: 2 } })],
|
|
88
|
+
probedAt: 1_000_000,
|
|
89
|
+
secret: SECRET,
|
|
90
|
+
});
|
|
91
|
+
expect(r.metrics.latencyScore).toBe(1.0);
|
|
92
|
+
expect(r.metrics.errorRate).toBe(0);
|
|
93
|
+
expect(r.metrics.utilityScore).toBe(1.0);
|
|
94
|
+
expect(r.metrics.outputEntropy).toBeGreaterThan(0);
|
|
95
|
+
expect(verifyProbeReport(r, SECRET)).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
it("counts synthetic + real inputs separately", () => {
|
|
98
|
+
const r = finaliseProbe({
|
|
99
|
+
toolName: "mneme.x",
|
|
100
|
+
runs: [
|
|
101
|
+
run({ inputSource: "synthetic" }), run({ inputSource: "synthetic" }),
|
|
102
|
+
run({ inputSource: "real" }),
|
|
103
|
+
],
|
|
104
|
+
probedAt: 0,
|
|
105
|
+
secret: SECRET,
|
|
106
|
+
});
|
|
107
|
+
expect(r.syntheticInputs).toBe(2);
|
|
108
|
+
expect(r.realInputs).toBe(1);
|
|
109
|
+
expect(r.totalInputs).toBe(3);
|
|
110
|
+
});
|
|
111
|
+
it("verify rejects tampered fitness", () => {
|
|
112
|
+
const r = finaliseProbe({ toolName: "x", runs: [run()], probedAt: 0, secret: SECRET });
|
|
113
|
+
expect(verifyProbeReport({ ...r, metrics: { ...r.metrics, fitnessScore: 0.99 } }, SECRET)).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
it("MEASURED 100% determinism: same input -> same sig (30 trials)", () => {
|
|
116
|
+
const input = {
|
|
117
|
+
toolName: "mneme.x",
|
|
118
|
+
runs: [run({ latencyMs: 50 }), run({ latencyMs: 70 })],
|
|
119
|
+
probedAt: 1_000_000,
|
|
120
|
+
secret: SECRET,
|
|
121
|
+
};
|
|
122
|
+
const firstSig = finaliseProbe(input).sig;
|
|
123
|
+
let allEqual = true;
|
|
124
|
+
for (let i = 0; i < 30; i++) {
|
|
125
|
+
if (finaliseProbe(input).sig !== firstSig) {
|
|
126
|
+
allEqual = false;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
expect(allEqual).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe("v2.19.27 PROBE · runProbeBattery (real invoke)", () => {
|
|
134
|
+
it("invokes each input + measures latency + catches errors", async () => {
|
|
135
|
+
const inputs = [
|
|
136
|
+
{ label: "axiom:1", source: "synthetic", args: { x: 1 } },
|
|
137
|
+
{ label: "axiom:2", source: "synthetic", args: { x: 2 } },
|
|
138
|
+
{ label: "real:1", source: "real", args: { x: 3 } },
|
|
139
|
+
];
|
|
140
|
+
const invoke = async (_t, args) => ({ doubled: args["x"] * 2 });
|
|
141
|
+
const r = await runProbeBattery({ toolName: "mneme.double", inputs, invoke, secret: SECRET });
|
|
142
|
+
expect(r.runs.length).toBe(3);
|
|
143
|
+
expect(r.runs.every((x) => x.ok)).toBe(true);
|
|
144
|
+
expect(r.syntheticInputs).toBe(2);
|
|
145
|
+
expect(r.realInputs).toBe(1);
|
|
146
|
+
expect(r.metrics.errorRate).toBe(0);
|
|
147
|
+
expect(r.metrics.utilityScore).toBe(1);
|
|
148
|
+
});
|
|
149
|
+
it("captures errors with messages without crashing the battery", async () => {
|
|
150
|
+
const inputs = [{ label: "x", source: "synthetic", args: {} }];
|
|
151
|
+
const invoke = async () => { throw new Error("kaboom"); };
|
|
152
|
+
const r = await runProbeBattery({ toolName: "mneme.broken", inputs, invoke, secret: SECRET });
|
|
153
|
+
expect(r.runs[0].ok).toBe(false);
|
|
154
|
+
expect(r.runs[0].errorMessage).toBe("kaboom");
|
|
155
|
+
expect(r.metrics.errorRate).toBe(1);
|
|
156
|
+
});
|
|
157
|
+
it("slow tool incurs latency penalty", async () => {
|
|
158
|
+
const inputs = [{ label: "x", source: "synthetic", args: {} }];
|
|
159
|
+
const invoke = async () => {
|
|
160
|
+
await new Promise((res) => setTimeout(res, 250));
|
|
161
|
+
return "done";
|
|
162
|
+
};
|
|
163
|
+
const r = await runProbeBattery({ toolName: "mneme.slow", inputs, invoke, secret: SECRET });
|
|
164
|
+
expect(r.metrics.latencyScore).toBeLessThan(1);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe("v2.19.27 PROBE · formatter", () => {
|
|
168
|
+
it("formatProbeLine includes all 4 metric percentages", () => {
|
|
169
|
+
const r = finaliseProbe({ toolName: "mneme.x", runs: [run()], probedAt: 0, secret: SECRET });
|
|
170
|
+
const line = formatProbeLine(r);
|
|
171
|
+
expect(line).toContain("PROBE mneme.x");
|
|
172
|
+
expect(line).toContain("fitness=");
|
|
173
|
+
expect(line).toContain("lat=");
|
|
174
|
+
expect(line).toContain("ent=");
|
|
175
|
+
expect(line).toContain("err=");
|
|
176
|
+
expect(line).toContain("util=");
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
//# sourceMappingURL=dreamspace_probe.test.js.map
|