@longarc/mdash 3.1.1 → 3.1.3
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/README.md +86 -23
- package/SECURITY.md +254 -0
- package/dist/accountability/engine.d.ts +27 -0
- package/dist/accountability/engine.d.ts.map +1 -0
- package/dist/accountability/engine.js +148 -0
- package/dist/accountability/engine.js.map +1 -0
- package/dist/accountability/types.d.ts +46 -0
- package/dist/accountability/types.d.ts.map +1 -0
- package/dist/accountability/types.js +8 -0
- package/dist/accountability/types.js.map +1 -0
- package/dist/checkpoint/engine.d.ts +2 -2
- package/dist/checkpoint/engine.d.ts.map +1 -1
- package/dist/checkpoint/engine.js +5 -1
- package/dist/checkpoint/engine.js.map +1 -1
- package/dist/context/compose.d.ts +62 -0
- package/dist/context/compose.d.ts.map +1 -0
- package/dist/context/compose.js +286 -0
- package/dist/context/compose.js.map +1 -0
- package/dist/context/crypto/hash.d.ts +100 -0
- package/dist/context/crypto/hash.d.ts.map +1 -0
- package/dist/context/crypto/hash.js +248 -0
- package/dist/context/crypto/hash.js.map +1 -0
- package/dist/context/crypto/hmac.d.ts +80 -0
- package/dist/context/crypto/hmac.d.ts.map +1 -0
- package/dist/context/crypto/hmac.js +192 -0
- package/dist/context/crypto/hmac.js.map +1 -0
- package/dist/context/crypto/index.d.ts +7 -0
- package/dist/context/crypto/index.d.ts.map +1 -0
- package/dist/context/crypto/index.js +7 -0
- package/dist/context/crypto/index.js.map +1 -0
- package/dist/context/engine-v3.0-backup.d.ts +197 -0
- package/dist/context/engine-v3.0-backup.d.ts.map +1 -0
- package/dist/context/engine-v3.0-backup.js +392 -0
- package/dist/context/engine-v3.0-backup.js.map +1 -0
- package/dist/context/engine.d.ts +2 -2
- package/dist/context/engine.d.ts.map +1 -1
- package/dist/context/engine.js +2 -2
- package/dist/context/engine.js.map +1 -1
- package/dist/context/fragment.d.ts +99 -0
- package/dist/context/fragment.d.ts.map +1 -0
- package/dist/context/fragment.js +316 -0
- package/dist/context/fragment.js.map +1 -0
- package/dist/context/index.d.ts +99 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +180 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/provenance.d.ts +80 -0
- package/dist/context/provenance.d.ts.map +1 -0
- package/dist/context/provenance.js +294 -0
- package/dist/context/provenance.js.map +1 -0
- package/dist/context/resolve.d.ts +106 -0
- package/dist/context/resolve.d.ts.map +1 -0
- package/dist/context/resolve.js +440 -0
- package/dist/context/resolve.js.map +1 -0
- package/dist/context/store.d.ts +156 -0
- package/dist/context/store.d.ts.map +1 -0
- package/dist/context/store.js +396 -0
- package/dist/context/store.js.map +1 -0
- package/dist/context/types.d.ts +463 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +94 -0
- package/dist/context/types.js.map +1 -0
- package/dist/context/utils/atomic.d.ts +76 -0
- package/dist/context/utils/atomic.d.ts.map +1 -0
- package/dist/context/utils/atomic.js +159 -0
- package/dist/context/utils/atomic.js.map +1 -0
- package/dist/context/utils/credit.d.ts +65 -0
- package/dist/context/utils/credit.d.ts.map +1 -0
- package/dist/context/utils/credit.js +164 -0
- package/dist/context/utils/credit.js.map +1 -0
- package/dist/context/utils/index.d.ts +13 -0
- package/dist/context/utils/index.d.ts.map +1 -0
- package/dist/context/utils/index.js +13 -0
- package/dist/context/utils/index.js.map +1 -0
- package/dist/context/utils/utility.d.ts +63 -0
- package/dist/context/utils/utility.d.ts.map +1 -0
- package/dist/context/utils/utility.js +141 -0
- package/dist/context/utils/utility.js.map +1 -0
- package/dist/core/commitment.d.ts +26 -3
- package/dist/core/commitment.d.ts.map +1 -1
- package/dist/core/commitment.js +45 -7
- package/dist/core/commitment.js.map +1 -1
- package/dist/core/crypto.d.ts +2 -0
- package/dist/core/crypto.d.ts.map +1 -1
- package/dist/core/crypto.js +12 -0
- package/dist/core/crypto.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -10
- package/dist/index.js.map +1 -1
- package/dist/mcca/engine.d.ts.map +1 -1
- package/dist/mcca/engine.js +5 -4
- package/dist/mcca/engine.js.map +1 -1
- package/dist/physics/engine.d.ts +3 -2
- package/dist/physics/engine.d.ts.map +1 -1
- package/dist/physics/engine.js +37 -3
- package/dist/physics/engine.js.map +1 -1
- package/dist/provenance/api-handler.d.ts +45 -0
- package/dist/provenance/api-handler.d.ts.map +1 -0
- package/dist/provenance/api-handler.js +223 -0
- package/dist/provenance/api-handler.js.map +1 -0
- package/dist/provenance/api-types.d.ts +108 -0
- package/dist/provenance/api-types.d.ts.map +1 -0
- package/dist/provenance/api-types.js +9 -0
- package/dist/provenance/api-types.js.map +1 -0
- package/dist/provenance/index.d.ts +6 -0
- package/dist/provenance/index.d.ts.map +1 -0
- package/dist/provenance/index.js +3 -0
- package/dist/provenance/index.js.map +1 -0
- package/dist/provenance/provenance-engine.d.ts +63 -0
- package/dist/provenance/provenance-engine.d.ts.map +1 -0
- package/dist/provenance/provenance-engine.js +311 -0
- package/dist/provenance/provenance-engine.js.map +1 -0
- package/dist/provenance/types.d.ts +193 -0
- package/dist/provenance/types.d.ts.map +1 -0
- package/dist/provenance/types.js +9 -0
- package/dist/provenance/types.js.map +1 -0
- package/dist/tee/engine.d.ts.map +1 -1
- package/dist/tee/engine.js +14 -0
- package/dist/tee/engine.js.map +1 -1
- package/dist/warrant/engine.d.ts +24 -1
- package/dist/warrant/engine.d.ts.map +1 -1
- package/dist/warrant/engine.js +76 -1
- package/dist/warrant/engine.js.map +1 -1
- package/dist/zk/engine.d.ts.map +1 -1
- package/dist/zk/engine.js +7 -4
- package/dist/zk/engine.js.map +1 -1
- package/docs/SECURITY-PATCHES.md +170 -0
- package/package.json +17 -5
- package/src/__tests__/accountability.test.ts +308 -0
- package/src/__tests__/l1-verification-modes.test.ts +424 -0
- package/src/__tests__/phase1.benchmark.test.ts +94 -0
- package/src/__tests__/phase1.test.ts +0 -77
- package/src/__tests__/phase2-4.benchmark.test.ts +60 -0
- package/src/__tests__/phase2-4.test.ts +1 -52
- package/src/__tests__/provenance/api-handler.test.ts +356 -0
- package/src/__tests__/provenance/provenance-engine.test.ts +628 -0
- package/src/__tests__/sa-2026-008.test.ts +45 -0
- package/src/__tests__/sa-2026-009.test.ts +86 -0
- package/src/__tests__/sa-2026-010.test.ts +72 -0
- package/src/__tests__/sa-2026-012.test.ts +65 -0
- package/src/__tests__/sa-2026-nfc.test.ts +40 -0
- package/src/__tests__/security.test.ts +786 -0
- package/src/accountability/engine.ts +230 -0
- package/src/accountability/types.ts +58 -0
- package/src/checkpoint/engine.ts +6 -2
- package/src/context/__tests__/caret-v0.2.0.test.ts +860 -0
- package/src/context/__tests__/integration.test.ts +356 -0
- package/src/context/compose.ts +388 -0
- package/src/context/crypto/hash.ts +277 -0
- package/src/context/crypto/hmac.ts +253 -0
- package/src/context/crypto/index.ts +29 -0
- package/src/context/engine-v3.0-backup.ts +598 -0
- package/src/context/engine.ts +2 -2
- package/src/context/fragment.ts +454 -0
- package/src/context/index.ts +427 -0
- package/src/context/provenance.ts +380 -0
- package/src/context/resolve.ts +581 -0
- package/src/context/store.ts +503 -0
- package/src/context/types.ts +679 -0
- package/src/context/utils/atomic.ts +207 -0
- package/src/context/utils/credit.ts +224 -0
- package/src/context/utils/index.ts +13 -0
- package/src/context/utils/utility.ts +200 -0
- package/src/core/commitment.ts +130 -68
- package/src/core/crypto.ts +13 -0
- package/src/index.ts +62 -10
- package/src/mcca/engine.ts +5 -4
- package/src/physics/engine.ts +42 -5
- package/src/provenance/api-handler.ts +248 -0
- package/src/provenance/api-types.ts +112 -0
- package/src/provenance/index.ts +19 -0
- package/src/provenance/provenance-engine.ts +387 -0
- package/src/provenance/types.ts +211 -0
- package/src/tee/engine.ts +16 -0
- package/src/warrant/engine.ts +89 -1
- package/src/zk/engine.ts +8 -4
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,860 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caret Engine v0.2.0 Test Suite
|
|
3
|
+
* Now integrated as mdash Context Module v3.1
|
|
4
|
+
*
|
|
5
|
+
* Comprehensive tests for research pattern integration:
|
|
6
|
+
* - Core runtime (seal, compose, resolve)
|
|
7
|
+
* - Utility learning
|
|
8
|
+
* - Credit assignment
|
|
9
|
+
* - Keyword search (Three-Layer Index Layer 2)
|
|
10
|
+
* - Semantic similarity (Three-Layer Index Layer 1)
|
|
11
|
+
* - Atomic encoding utilities
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, test, expect, beforeEach } from 'vitest';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
createCaret,
|
|
18
|
+
MemoryStore,
|
|
19
|
+
ExtendedMemoryStore,
|
|
20
|
+
VERSION,
|
|
21
|
+
// Crypto
|
|
22
|
+
sha256,
|
|
23
|
+
sha256Object,
|
|
24
|
+
hmacSeal,
|
|
25
|
+
hmacVerify,
|
|
26
|
+
// Types
|
|
27
|
+
type ContextFragment,
|
|
28
|
+
type ExecutionTrace,
|
|
29
|
+
type InfluenceBudget,
|
|
30
|
+
type UtilityScore,
|
|
31
|
+
type Timestamp,
|
|
32
|
+
type FragmentId,
|
|
33
|
+
// Constraint builders
|
|
34
|
+
maxAge,
|
|
35
|
+
requireTrust,
|
|
36
|
+
requireInfluence,
|
|
37
|
+
requireMCCA,
|
|
38
|
+
// Utility learning
|
|
39
|
+
updateUtilityScore,
|
|
40
|
+
createInitialUtility,
|
|
41
|
+
predictSuccess,
|
|
42
|
+
// Credit assignment
|
|
43
|
+
assignCredit,
|
|
44
|
+
validateCreditAssignment,
|
|
45
|
+
attributeLiability,
|
|
46
|
+
validateLiabilityShares,
|
|
47
|
+
createDefaultInfluenceBudget,
|
|
48
|
+
isMCCACompliant,
|
|
49
|
+
normalizeInfluenceBudget,
|
|
50
|
+
// Atomic encoding
|
|
51
|
+
resolveCoreferences,
|
|
52
|
+
createDefaultContext,
|
|
53
|
+
hasUnresolvedCoreferences,
|
|
54
|
+
canonicalEncode,
|
|
55
|
+
isValidSubject,
|
|
56
|
+
isValidTimestamp,
|
|
57
|
+
// Type guards
|
|
58
|
+
isValidInfluenceBudget,
|
|
59
|
+
sumInfluence,
|
|
60
|
+
} from '../index.js';
|
|
61
|
+
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// TEST UTILITIES
|
|
64
|
+
// ============================================================================
|
|
65
|
+
|
|
66
|
+
const SEAL_KEY = 'test-secret-key-do-not-use-in-production-32';
|
|
67
|
+
|
|
68
|
+
function createTestTrace(steps: number = 3): ExecutionTrace {
|
|
69
|
+
const traceSteps = [];
|
|
70
|
+
for (let i = 0; i < steps; i++) {
|
|
71
|
+
traceSteps.push({
|
|
72
|
+
step_id: `Agent_${i.toString().padStart(4, '0')}_step_${i}`,
|
|
73
|
+
timestamp: new Date(Date.now() + i * 1000).toISOString() as Timestamp,
|
|
74
|
+
action: 'INVOKE' as const,
|
|
75
|
+
observation_hash: `hash_${i}`,
|
|
76
|
+
influence_consumed: {
|
|
77
|
+
system: 0.1,
|
|
78
|
+
user: 0.05,
|
|
79
|
+
environment: 0.03,
|
|
80
|
+
assistant: 0.02,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
trace_id: `trace_${Date.now()}` as FragmentId,
|
|
87
|
+
steps: traceSteps,
|
|
88
|
+
outcome: 'success',
|
|
89
|
+
terminal_state: 'completed',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// VERSION & BASIC TESTS
|
|
95
|
+
// ============================================================================
|
|
96
|
+
|
|
97
|
+
describe('Caret Core', () => {
|
|
98
|
+
test('VERSION is 0.2.0', () => {
|
|
99
|
+
expect(VERSION).toBe('3.1.0');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('createCaret requires seal_key', () => {
|
|
103
|
+
expect(() => createCaret({ seal_key: '' })).toThrow();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('createCaret enforces minimum key length', () => {
|
|
107
|
+
expect(() => createCaret({ seal_key: 'short' })).toThrow('at least 32');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('createCaret creates runtime with valid key', () => {
|
|
111
|
+
const caret = createCaret({ seal_key: SEAL_KEY });
|
|
112
|
+
expect(caret).toBeDefined();
|
|
113
|
+
expect(caret.seal).toBeDefined();
|
|
114
|
+
expect(caret.compose).toBeDefined();
|
|
115
|
+
expect(caret.resolve).toBeDefined();
|
|
116
|
+
expect(caret.store).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// CRYPTO TESTS
|
|
122
|
+
// ============================================================================
|
|
123
|
+
|
|
124
|
+
describe('Crypto', () => {
|
|
125
|
+
test('sha256 produces consistent hashes', async () => {
|
|
126
|
+
const hash1 = await sha256('hello world');
|
|
127
|
+
const hash2 = await sha256('hello world');
|
|
128
|
+
expect(hash1).toBe(hash2);
|
|
129
|
+
expect(hash1.length).toBe(64);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('sha256 produces different hashes for different inputs', async () => {
|
|
133
|
+
const hash1 = await sha256('hello');
|
|
134
|
+
const hash2 = await sha256('world');
|
|
135
|
+
expect(hash1).not.toBe(hash2);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('sha256Object is deterministic with sorted keys', async () => {
|
|
139
|
+
const hash1 = await sha256Object({ b: 2, a: 1 });
|
|
140
|
+
const hash2 = await sha256Object({ a: 1, b: 2 });
|
|
141
|
+
expect(hash1).toBe(hash2);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('hmacSeal produces verifiable seals', async () => {
|
|
145
|
+
const content = { message: 'test' };
|
|
146
|
+
const seal = await hmacSeal(content, SEAL_KEY);
|
|
147
|
+
const isValid = await hmacVerify(content, seal, SEAL_KEY);
|
|
148
|
+
expect(isValid).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('hmacVerify rejects tampered content', async () => {
|
|
152
|
+
const content = { message: 'test' };
|
|
153
|
+
const seal = await hmacSeal(content, SEAL_KEY);
|
|
154
|
+
const tampered = { message: 'tampered' };
|
|
155
|
+
const isValid = await hmacVerify(tampered, seal, SEAL_KEY);
|
|
156
|
+
expect(isValid).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// FRAGMENT TESTS
|
|
162
|
+
// ============================================================================
|
|
163
|
+
|
|
164
|
+
describe('Fragment Operations', () => {
|
|
165
|
+
let caret: ReturnType<typeof createCaret>;
|
|
166
|
+
|
|
167
|
+
beforeEach(() => {
|
|
168
|
+
caret = createCaret({ seal_key: SEAL_KEY });
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test('seal creates valid fragment', async () => {
|
|
172
|
+
const fragment = await caret.seal({
|
|
173
|
+
content: { message: 'hello' },
|
|
174
|
+
source: 'test://example' as any,
|
|
175
|
+
attribution: 'system',
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
expect(fragment.id).toBeDefined();
|
|
179
|
+
expect(fragment.hash).toBeDefined();
|
|
180
|
+
expect(fragment.seal).toBeDefined();
|
|
181
|
+
expect(fragment.content.data).toEqual({ message: 'hello' });
|
|
182
|
+
expect(fragment.version).toBe('v3.1');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('seal with trust level', async () => {
|
|
186
|
+
const fragment = await caret.seal({
|
|
187
|
+
content: 'test',
|
|
188
|
+
source: 'test://example' as any,
|
|
189
|
+
attribution: 'user',
|
|
190
|
+
trust_level: 80 as any,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(fragment.provenance.head.trust_level).toBe(80);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test('verify returns true for valid fragment', async () => {
|
|
197
|
+
const fragment = await caret.seal({
|
|
198
|
+
content: 'verify test',
|
|
199
|
+
source: 'test://verify' as any,
|
|
200
|
+
attribution: 'system',
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const isValid = await caret.verify(fragment);
|
|
204
|
+
expect(isValid).toBe(true);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// CONSTRAINT TESTS
|
|
210
|
+
// ============================================================================
|
|
211
|
+
|
|
212
|
+
describe('Constraints', () => {
|
|
213
|
+
let caret: ReturnType<typeof createCaret>;
|
|
214
|
+
|
|
215
|
+
beforeEach(() => {
|
|
216
|
+
caret = createCaret({ seal_key: SEAL_KEY });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test('maxAge constraint', async () => {
|
|
220
|
+
const fragment = await caret.seal({
|
|
221
|
+
content: 'age test',
|
|
222
|
+
source: 'test://age' as any,
|
|
223
|
+
attribution: 'system',
|
|
224
|
+
constraints: [maxAge(60000)],
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const result = await caret.resolve(fragment);
|
|
228
|
+
expect(result.success).toBe(true);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('requireTrust constraint', async () => {
|
|
232
|
+
const fragment = await caret.seal({
|
|
233
|
+
content: 'trust test',
|
|
234
|
+
source: 'test://trust' as any,
|
|
235
|
+
attribution: 'system',
|
|
236
|
+
trust_level: 90 as any,
|
|
237
|
+
constraints: [requireTrust(80)],
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const result = await caret.resolve(fragment);
|
|
241
|
+
expect(result.success).toBe(true);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test('requireInfluence constraint', async () => {
|
|
245
|
+
const budget: InfluenceBudget = {
|
|
246
|
+
system: 0.45,
|
|
247
|
+
user: 0.30,
|
|
248
|
+
environment: 0.15,
|
|
249
|
+
assistant: 0.10,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const constraint = requireInfluence(budget);
|
|
253
|
+
expect(constraint.kind).toBe('influence');
|
|
254
|
+
expect(constraint.budget).toEqual(budget);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('requireMCCA constraint creates MCCA-compliant budget', () => {
|
|
258
|
+
const constraint = requireMCCA();
|
|
259
|
+
expect(constraint.kind).toBe('influence');
|
|
260
|
+
expect(isMCCACompliant(constraint.budget)).toBe(true);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// ============================================================================
|
|
265
|
+
// UTILITY LEARNING TESTS
|
|
266
|
+
// ============================================================================
|
|
267
|
+
|
|
268
|
+
describe('Utility Learning', () => {
|
|
269
|
+
test('createInitialUtility creates valid utility score', () => {
|
|
270
|
+
const utility = createInitialUtility();
|
|
271
|
+
expect(utility.score).toBe(0);
|
|
272
|
+
expect(utility.confidence).toBe(0);
|
|
273
|
+
expect(utility.update_count).toBe(0);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test('updateUtilityScore increments correctly', () => {
|
|
277
|
+
const initial = createInitialUtility();
|
|
278
|
+
const feedback = {
|
|
279
|
+
reward: 1.0,
|
|
280
|
+
source: 'human' as const,
|
|
281
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const updated = updateUtilityScore(initial, feedback);
|
|
285
|
+
|
|
286
|
+
expect(updated.score).toBeGreaterThan(0);
|
|
287
|
+
expect(updated.update_count).toBe(1);
|
|
288
|
+
expect(updated.confidence).toBeGreaterThan(0);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test('updateUtilityScore bounds score to [-1, 1]', () => {
|
|
292
|
+
let utility = createInitialUtility();
|
|
293
|
+
|
|
294
|
+
// Push score high
|
|
295
|
+
for (let i = 0; i < 20; i++) {
|
|
296
|
+
utility = updateUtilityScore(utility, {
|
|
297
|
+
reward: 1.0,
|
|
298
|
+
source: 'system' as const,
|
|
299
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
expect(utility.score).toBeLessThanOrEqual(1.0);
|
|
304
|
+
expect(utility.score).toBeGreaterThanOrEqual(-1.0);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test('updateUtilityScore increases confidence with updates', () => {
|
|
308
|
+
let utility = createInitialUtility();
|
|
309
|
+
const confidences: number[] = [utility.confidence];
|
|
310
|
+
|
|
311
|
+
for (let i = 0; i < 10; i++) {
|
|
312
|
+
utility = updateUtilityScore(utility, {
|
|
313
|
+
reward: 0.5,
|
|
314
|
+
source: 'environment' as const,
|
|
315
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
316
|
+
});
|
|
317
|
+
confidences.push(utility.confidence);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Each confidence should be >= previous
|
|
321
|
+
for (let i = 1; i < confidences.length; i++) {
|
|
322
|
+
expect(confidences[i]).toBeGreaterThanOrEqual(confidences[i-1]!);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test('predictSuccess returns prior for empty history', () => {
|
|
327
|
+
const prediction = predictSuccess([]);
|
|
328
|
+
expect(prediction).toBe(0.5);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// ============================================================================
|
|
333
|
+
// CREDIT ASSIGNMENT TESTS
|
|
334
|
+
// ============================================================================
|
|
335
|
+
|
|
336
|
+
describe('Credit Assignment', () => {
|
|
337
|
+
test('assignCredit distributes terminal reward', () => {
|
|
338
|
+
const trace = createTestTrace(3);
|
|
339
|
+
const terminalReward = 1.0;
|
|
340
|
+
|
|
341
|
+
const assignment = assignCredit(trace, terminalReward);
|
|
342
|
+
|
|
343
|
+
expect(assignment.trace_id).toBe(trace.trace_id);
|
|
344
|
+
expect(assignment.terminal_reward).toBe(terminalReward);
|
|
345
|
+
expect(assignment.step_credits.length).toBe(3);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test('assignCredit conserves terminal reward', () => {
|
|
349
|
+
const trace = createTestTrace(5);
|
|
350
|
+
const terminalReward = 10.0;
|
|
351
|
+
|
|
352
|
+
const assignment = assignCredit(trace, terminalReward);
|
|
353
|
+
|
|
354
|
+
expect(validateCreditAssignment(assignment)).toBe(true);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test('assignCredit proportional to influence', () => {
|
|
358
|
+
// Create trace with unequal influence
|
|
359
|
+
const trace: ExecutionTrace = {
|
|
360
|
+
trace_id: 'test_trace' as FragmentId,
|
|
361
|
+
steps: [
|
|
362
|
+
{
|
|
363
|
+
step_id: 'Agent_0001_step_0',
|
|
364
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
365
|
+
action: 'INVOKE',
|
|
366
|
+
observation_hash: 'hash_0',
|
|
367
|
+
influence_consumed: { system: 0.4, user: 0.3, environment: 0.2, assistant: 0.1 },
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
step_id: 'Agent_0002_step_1',
|
|
371
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
372
|
+
action: 'CHECKPOINT',
|
|
373
|
+
observation_hash: 'hash_1',
|
|
374
|
+
influence_consumed: { system: 0.1, user: 0.05, environment: 0.03, assistant: 0.02 },
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
outcome: 'success',
|
|
378
|
+
terminal_state: 'done',
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const assignment = assignCredit(trace, 1.0);
|
|
382
|
+
|
|
383
|
+
// First step has more influence, should get more credit
|
|
384
|
+
expect(assignment.step_credits[0]!.credit).toBeGreaterThan(assignment.step_credits[1]!.credit);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test('attributeLiability groups by agent', () => {
|
|
388
|
+
const trace: ExecutionTrace = {
|
|
389
|
+
trace_id: 'liability_trace' as FragmentId,
|
|
390
|
+
steps: [
|
|
391
|
+
{
|
|
392
|
+
step_id: 'Agent_aaa1_step_0',
|
|
393
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
394
|
+
action: 'INVOKE',
|
|
395
|
+
observation_hash: 'h0',
|
|
396
|
+
influence_consumed: { system: 0.2, user: 0.1, environment: 0.1, assistant: 0.1 },
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
step_id: 'Agent_bbb2_step_1',
|
|
400
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
401
|
+
action: 'CHECKPOINT',
|
|
402
|
+
observation_hash: 'h1',
|
|
403
|
+
influence_consumed: { system: 0.2, user: 0.1, environment: 0.1, assistant: 0.1 },
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
step_id: 'Agent_aaa1_step_2',
|
|
407
|
+
timestamp: new Date().toISOString() as Timestamp,
|
|
408
|
+
action: 'TERMINATE',
|
|
409
|
+
observation_hash: 'h2',
|
|
410
|
+
influence_consumed: { system: 0.2, user: 0.1, environment: 0.1, assistant: 0.1 },
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
outcome: 'success',
|
|
414
|
+
terminal_state: 'done',
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const liability = attributeLiability(trace);
|
|
418
|
+
|
|
419
|
+
// Should have 2 agents
|
|
420
|
+
expect(liability.length).toBe(2);
|
|
421
|
+
expect(validateLiabilityShares(liability)).toBe(true);
|
|
422
|
+
|
|
423
|
+
// Agent_aaa1 should have more liability (2 steps vs 1)
|
|
424
|
+
const agentA = liability.find(l => l.agent_id.includes('aaa1'));
|
|
425
|
+
const agentB = liability.find(l => l.agent_id.includes('bbb2'));
|
|
426
|
+
expect(agentA!.contribution).toBeGreaterThan(agentB!.contribution);
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// ============================================================================
|
|
431
|
+
// INFLUENCE BUDGET TESTS
|
|
432
|
+
// ============================================================================
|
|
433
|
+
|
|
434
|
+
describe('Influence Budget', () => {
|
|
435
|
+
test('createDefaultInfluenceBudget creates valid budget', () => {
|
|
436
|
+
const budget = createDefaultInfluenceBudget();
|
|
437
|
+
expect(isValidInfluenceBudget(budget)).toBe(true);
|
|
438
|
+
expect(isMCCACompliant(budget)).toBe(true);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test('isMCCACompliant validates bounds', () => {
|
|
442
|
+
// Valid
|
|
443
|
+
expect(isMCCACompliant({ system: 0.45, user: 0.30, environment: 0.15, assistant: 0.10 })).toBe(true);
|
|
444
|
+
|
|
445
|
+
// Invalid: system too low
|
|
446
|
+
expect(isMCCACompliant({ system: 0.35, user: 0.30, environment: 0.20, assistant: 0.15 })).toBe(false);
|
|
447
|
+
|
|
448
|
+
// Invalid: user too high
|
|
449
|
+
expect(isMCCACompliant({ system: 0.40, user: 0.40, environment: 0.10, assistant: 0.10 })).toBe(false);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
test('normalizeInfluenceBudget sums to 1.0', () => {
|
|
453
|
+
const unnormalized = { system: 0.8, user: 0.4, environment: 0.2, assistant: 0.1 };
|
|
454
|
+
const normalized = normalizeInfluenceBudget(unnormalized);
|
|
455
|
+
|
|
456
|
+
const sum = sumInfluence(normalized);
|
|
457
|
+
expect(Math.abs(sum - 1.0)).toBeLessThan(0.001);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test('sumInfluence computes total', () => {
|
|
461
|
+
const budget = { system: 0.4, user: 0.3, environment: 0.2, assistant: 0.1 };
|
|
462
|
+
expect(sumInfluence(budget)).toBeCloseTo(1.0);
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// ============================================================================
|
|
467
|
+
// ATOMIC ENCODING TESTS
|
|
468
|
+
// ============================================================================
|
|
469
|
+
|
|
470
|
+
describe('Atomic Encoding', () => {
|
|
471
|
+
test('resolveCoreferences replaces pronouns', () => {
|
|
472
|
+
const context = createDefaultContext();
|
|
473
|
+
context.lastAgentId = 'Agent_abc123';
|
|
474
|
+
|
|
475
|
+
const text = 'He approved the request';
|
|
476
|
+
const resolved = resolveCoreferences(text, context);
|
|
477
|
+
|
|
478
|
+
expect(resolved).toContain('Agent_abc123');
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test('resolveCoreferences replaces relative time', () => {
|
|
482
|
+
const context = createDefaultContext();
|
|
483
|
+
const refDate = new Date('2026-01-18T12:00:00Z');
|
|
484
|
+
context.referenceTime = refDate.toISOString();
|
|
485
|
+
|
|
486
|
+
const text = 'Approved yesterday';
|
|
487
|
+
const resolved = resolveCoreferences(text, context);
|
|
488
|
+
|
|
489
|
+
// Should contain ISO timestamp, not "yesterday"
|
|
490
|
+
expect(resolved).not.toContain('yesterday');
|
|
491
|
+
expect(resolved).toContain('2026-01-17');
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
test('hasUnresolvedCoreferences detects pronouns', () => {
|
|
495
|
+
expect(hasUnresolvedCoreferences('He did it')).toBe(true);
|
|
496
|
+
expect(hasUnresolvedCoreferences('Agent_123 invoked Warrant_456')).toBe(false);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
test('canonicalEncode produces deterministic output', () => {
|
|
500
|
+
const attestation = {
|
|
501
|
+
subject: 'Agent_abc',
|
|
502
|
+
action: 'INVOKE' as const,
|
|
503
|
+
timestamp: '2026-01-18T00:00:00Z',
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
const encoded1 = canonicalEncode(attestation);
|
|
507
|
+
const encoded2 = canonicalEncode(attestation);
|
|
508
|
+
|
|
509
|
+
expect(encoded1).toBe(encoded2);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test('isValidSubject validates entity IDs', () => {
|
|
513
|
+
expect(isValidSubject('Agent_abc123')).toBe(true);
|
|
514
|
+
expect(isValidSubject('Warrant_def456')).toBe(true);
|
|
515
|
+
expect(isValidSubject('Checkpoint_abc789')).toBe(true); // hex only
|
|
516
|
+
expect(isValidSubject('User_012abc')).toBe(true);
|
|
517
|
+
expect(isValidSubject('invalid')).toBe(false);
|
|
518
|
+
expect(isValidSubject('Agent_xyz')).toBe(false); // xyz not hex
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
test('isValidTimestamp validates ISO 8601', () => {
|
|
522
|
+
expect(isValidTimestamp('2026-01-18T12:00:00Z')).toBe(true);
|
|
523
|
+
expect(isValidTimestamp('2026-01-18T12:00:00.123Z')).toBe(true);
|
|
524
|
+
expect(isValidTimestamp('yesterday')).toBe(false);
|
|
525
|
+
expect(isValidTimestamp('2026-01-18')).toBe(false);
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// ============================================================================
|
|
530
|
+
// KEYWORD SEARCH TESTS (Three-Layer Index Layer 2)
|
|
531
|
+
// ============================================================================
|
|
532
|
+
|
|
533
|
+
describe('Keyword Search (Layer 2)', () => {
|
|
534
|
+
let store: MemoryStore;
|
|
535
|
+
let caret: ReturnType<typeof createCaret>;
|
|
536
|
+
|
|
537
|
+
beforeEach(() => {
|
|
538
|
+
store = new MemoryStore(SEAL_KEY);
|
|
539
|
+
caret = createCaret({ seal_key: SEAL_KEY, store });
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
test('queryByKeywords finds matching fragments', async () => {
|
|
543
|
+
await caret.seal({
|
|
544
|
+
content: 'The quick brown fox jumps over the lazy dog',
|
|
545
|
+
source: 'test://keyword1' as any,
|
|
546
|
+
attribution: 'system',
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
await caret.seal({
|
|
550
|
+
content: 'A fast red cat sleeps on the mat',
|
|
551
|
+
source: 'test://keyword2' as any,
|
|
552
|
+
attribution: 'system',
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const results = await store.queryByKeywords(['fox']);
|
|
556
|
+
expect(results.length).toBe(1);
|
|
557
|
+
expect((results[0]!.content.data as string)).toContain('fox');
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test('queryByKeywords with matchMode any', async () => {
|
|
561
|
+
await caret.seal({
|
|
562
|
+
content: 'Document about cats and dogs',
|
|
563
|
+
source: 'test://any1' as any,
|
|
564
|
+
attribution: 'system',
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
await caret.seal({
|
|
568
|
+
content: 'Document about birds',
|
|
569
|
+
source: 'test://any2' as any,
|
|
570
|
+
attribution: 'system',
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
const results = await store.queryByKeywords(['cats', 'birds'], 'any');
|
|
574
|
+
expect(results.length).toBe(2);
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
test('queryByKeywords with matchMode all', async () => {
|
|
578
|
+
await caret.seal({
|
|
579
|
+
content: 'Document about cats and dogs',
|
|
580
|
+
source: 'test://all1' as any,
|
|
581
|
+
attribution: 'system',
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
await caret.seal({
|
|
585
|
+
content: 'Document about dogs only',
|
|
586
|
+
source: 'test://all2' as any,
|
|
587
|
+
attribution: 'system',
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
const results = await store.queryByKeywords(['cats', 'dogs'], 'all');
|
|
591
|
+
expect(results.length).toBe(1);
|
|
592
|
+
expect((results[0]!.content.data as string)).toContain('cats');
|
|
593
|
+
expect((results[0]!.content.data as string)).toContain('dogs');
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
test('queryByKeywords is case-insensitive', async () => {
|
|
597
|
+
await caret.seal({
|
|
598
|
+
content: 'UPPERCASE CONTENT',
|
|
599
|
+
source: 'test://case' as any,
|
|
600
|
+
attribution: 'system',
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
const results = await store.queryByKeywords(['uppercase']);
|
|
604
|
+
expect(results.length).toBe(1);
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
test('queryByKeywords searches object content', async () => {
|
|
608
|
+
await caret.seal({
|
|
609
|
+
content: { title: 'Meeting Notes', body: 'Discussed project alpha' },
|
|
610
|
+
source: 'test://object' as any,
|
|
611
|
+
attribution: 'system',
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
const results = await store.queryByKeywords(['alpha']);
|
|
615
|
+
expect(results.length).toBe(1);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
test('queryByKeywords returns empty for no matches', async () => {
|
|
619
|
+
await caret.seal({
|
|
620
|
+
content: 'Some unrelated content',
|
|
621
|
+
source: 'test://nomatch' as any,
|
|
622
|
+
attribution: 'system',
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
const results = await store.queryByKeywords(['xyz123']);
|
|
626
|
+
expect(results.length).toBe(0);
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
// ============================================================================
|
|
631
|
+
// SEMANTIC SIMILARITY TESTS (Three-Layer Index Layer 1)
|
|
632
|
+
// ============================================================================
|
|
633
|
+
|
|
634
|
+
describe('Semantic Similarity (Layer 1)', () => {
|
|
635
|
+
let store: ExtendedMemoryStore;
|
|
636
|
+
let caret: ReturnType<typeof createCaret>;
|
|
637
|
+
|
|
638
|
+
beforeEach(() => {
|
|
639
|
+
store = new ExtendedMemoryStore(SEAL_KEY);
|
|
640
|
+
caret = createCaret({ seal_key: SEAL_KEY, store });
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
test('ExtendedMemoryStore inherits MemoryStore methods', async () => {
|
|
644
|
+
const fragment = await caret.seal({
|
|
645
|
+
content: 'test content',
|
|
646
|
+
source: 'test://inherit' as any,
|
|
647
|
+
attribution: 'system',
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
const retrieved = await store.get(fragment.id);
|
|
651
|
+
expect(retrieved).not.toBeNull();
|
|
652
|
+
expect(retrieved!.id).toBe(fragment.id);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
test('setEmbedding stores embedding for fragment', async () => {
|
|
656
|
+
const fragment = await caret.seal({
|
|
657
|
+
content: 'semantic test',
|
|
658
|
+
source: 'test://embed' as any,
|
|
659
|
+
attribution: 'system',
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
const embedding = new Float32Array([0.1, 0.2, 0.3, 0.4]);
|
|
663
|
+
store.setEmbedding(fragment.id, embedding);
|
|
664
|
+
|
|
665
|
+
const stats = store.embeddingStats();
|
|
666
|
+
expect(stats.count).toBe(1);
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
test('queryBySimilarity finds similar fragments', async () => {
|
|
670
|
+
const fragment1 = await caret.seal({
|
|
671
|
+
content: 'machine learning is great',
|
|
672
|
+
source: 'test://sim1' as any,
|
|
673
|
+
attribution: 'system',
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
const fragment2 = await caret.seal({
|
|
677
|
+
content: 'cooking recipes for dinner',
|
|
678
|
+
source: 'test://sim2' as any,
|
|
679
|
+
attribution: 'system',
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
// Manually set embeddings (in real use, embedding function would do this)
|
|
683
|
+
const embedding1 = new Float32Array([0.9, 0.1, 0.0, 0.0]); // ML-like
|
|
684
|
+
const embedding2 = new Float32Array([0.0, 0.0, 0.9, 0.1]); // Cooking-like
|
|
685
|
+
|
|
686
|
+
store.setEmbedding(fragment1.id, embedding1);
|
|
687
|
+
store.setEmbedding(fragment2.id, embedding2);
|
|
688
|
+
|
|
689
|
+
// Query for ML-like content
|
|
690
|
+
const queryEmbedding = new Float32Array([0.8, 0.2, 0.0, 0.0]);
|
|
691
|
+
const results = await store.queryBySimilarity(queryEmbedding, 0.5, 10);
|
|
692
|
+
|
|
693
|
+
expect(results.length).toBeGreaterThan(0);
|
|
694
|
+
expect(results[0]!.fragment.id).toBe(fragment1.id); // ML doc should be first
|
|
695
|
+
expect(results[0]!.similarity).toBeGreaterThan(0.5);
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
test('queryBySimilarity respects threshold', async () => {
|
|
699
|
+
const fragment = await caret.seal({
|
|
700
|
+
content: 'test threshold',
|
|
701
|
+
source: 'test://threshold' as any,
|
|
702
|
+
attribution: 'system',
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
const embedding = new Float32Array([0.1, 0.0, 0.0, 0.9]);
|
|
706
|
+
store.setEmbedding(fragment.id, embedding);
|
|
707
|
+
|
|
708
|
+
// Query with orthogonal vector
|
|
709
|
+
const queryEmbedding = new Float32Array([0.9, 0.1, 0.0, 0.0]);
|
|
710
|
+
|
|
711
|
+
// High threshold should exclude
|
|
712
|
+
const highThreshold = await store.queryBySimilarity(queryEmbedding, 0.9, 10);
|
|
713
|
+
expect(highThreshold.length).toBe(0);
|
|
714
|
+
|
|
715
|
+
// Low threshold should include
|
|
716
|
+
const lowThreshold = await store.queryBySimilarity(queryEmbedding, 0.0, 10);
|
|
717
|
+
expect(lowThreshold.length).toBe(1);
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
test('queryBySimilarity respects limit', async () => {
|
|
721
|
+
// Create multiple fragments
|
|
722
|
+
for (let i = 0; i < 5; i++) {
|
|
723
|
+
const fragment = await caret.seal({
|
|
724
|
+
content: `document ${i}`,
|
|
725
|
+
source: `test://limit${i}` as any,
|
|
726
|
+
attribution: 'system',
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
// All similar embeddings
|
|
730
|
+
const embedding = new Float32Array([0.5, 0.5, 0.0, 0.0]);
|
|
731
|
+
store.setEmbedding(fragment.id, embedding);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const queryEmbedding = new Float32Array([0.5, 0.5, 0.0, 0.0]);
|
|
735
|
+
const results = await store.queryBySimilarity(queryEmbedding, 0.0, 3);
|
|
736
|
+
|
|
737
|
+
expect(results.length).toBe(3);
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
test('setEmbeddingFunction auto-embeds on put', async () => {
|
|
741
|
+
// Track calls to embedding function
|
|
742
|
+
let callCount = 0;
|
|
743
|
+
const mockEmbedFn = async (_text: string): Promise<Float32Array> => {
|
|
744
|
+
callCount++;
|
|
745
|
+
return new Float32Array([0.1, 0.2, 0.3, 0.4]);
|
|
746
|
+
};
|
|
747
|
+
store.setEmbeddingFunction(mockEmbedFn);
|
|
748
|
+
|
|
749
|
+
await caret.seal({
|
|
750
|
+
content: 'auto embed test',
|
|
751
|
+
source: 'test://autoembed' as any,
|
|
752
|
+
attribution: 'system',
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
expect(callCount).toBe(1);
|
|
756
|
+
expect(store.embeddingStats().count).toBe(1);
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
test('clearEmbeddings removes all embeddings', async () => {
|
|
760
|
+
const fragment = await caret.seal({
|
|
761
|
+
content: 'clear test',
|
|
762
|
+
source: 'test://clear' as any,
|
|
763
|
+
attribution: 'system',
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
store.setEmbedding(fragment.id, new Float32Array([0.1, 0.2, 0.3, 0.4]));
|
|
767
|
+
expect(store.embeddingStats().count).toBe(1);
|
|
768
|
+
|
|
769
|
+
store.clearEmbeddings();
|
|
770
|
+
expect(store.embeddingStats().count).toBe(0);
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// ============================================================================
|
|
775
|
+
// INTEGRATION TESTS
|
|
776
|
+
// ============================================================================
|
|
777
|
+
|
|
778
|
+
describe('Integration', () => {
|
|
779
|
+
test('full workflow: seal, resolve, assign credit', async () => {
|
|
780
|
+
const caret = createCaret({ seal_key: SEAL_KEY });
|
|
781
|
+
|
|
782
|
+
// 1. Seal a fragment
|
|
783
|
+
const fragment = await caret.seal({
|
|
784
|
+
content: { task: 'complete integration test' },
|
|
785
|
+
source: 'test://integration' as any,
|
|
786
|
+
attribution: 'system',
|
|
787
|
+
constraints: [
|
|
788
|
+
requireTrust(50),
|
|
789
|
+
requireMCCA(),
|
|
790
|
+
],
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
// 2. Resolve through constraints
|
|
794
|
+
const resolution = await caret.resolve(fragment, {
|
|
795
|
+
current_time: new Date().toISOString() as Timestamp,
|
|
796
|
+
current_domain: 'test',
|
|
797
|
+
current_trust: 100,
|
|
798
|
+
current_influence: createDefaultInfluenceBudget(),
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
expect(resolution.success).toBe(true);
|
|
802
|
+
|
|
803
|
+
// 3. Create execution trace
|
|
804
|
+
const trace = createTestTrace(4);
|
|
805
|
+
|
|
806
|
+
// 4. Assign credit
|
|
807
|
+
const credits = assignCredit(trace, 1.0);
|
|
808
|
+
expect(validateCreditAssignment(credits)).toBe(true);
|
|
809
|
+
|
|
810
|
+
// 5. Attribute liability
|
|
811
|
+
const liability = attributeLiability(trace);
|
|
812
|
+
expect(validateLiabilityShares(liability)).toBe(true);
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
test('three-layer index workflow', async () => {
|
|
816
|
+
const store = new ExtendedMemoryStore(SEAL_KEY);
|
|
817
|
+
const caret = createCaret({ seal_key: SEAL_KEY, store });
|
|
818
|
+
|
|
819
|
+
// Create documents
|
|
820
|
+
const doc1 = await caret.seal({
|
|
821
|
+
content: 'Machine learning models for NLP',
|
|
822
|
+
source: 'test://ml1' as any,
|
|
823
|
+
attribution: 'system',
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
const doc2 = await caret.seal({
|
|
827
|
+
content: 'Deep learning neural networks',
|
|
828
|
+
source: 'test://ml2' as any,
|
|
829
|
+
attribution: 'system',
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
const doc3 = await caret.seal({
|
|
833
|
+
content: 'Cooking pasta recipes',
|
|
834
|
+
source: 'test://cook' as any,
|
|
835
|
+
attribution: 'system',
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
// Set embeddings
|
|
839
|
+
store.setEmbedding(doc1.id, new Float32Array([0.9, 0.8, 0.1, 0.0]));
|
|
840
|
+
store.setEmbedding(doc2.id, new Float32Array([0.85, 0.75, 0.15, 0.05]));
|
|
841
|
+
store.setEmbedding(doc3.id, new Float32Array([0.1, 0.1, 0.9, 0.8]));
|
|
842
|
+
|
|
843
|
+
// Layer 2: Keyword search
|
|
844
|
+
const keywordResults = await store.queryByKeywords(['learning']);
|
|
845
|
+
expect(keywordResults.length).toBe(2); // doc1 and doc2
|
|
846
|
+
|
|
847
|
+
// Layer 1: Semantic search
|
|
848
|
+
const queryEmb = new Float32Array([0.9, 0.85, 0.1, 0.0]); // ML-like query
|
|
849
|
+
const semanticResults = await store.queryBySimilarity(queryEmb, 0.8, 5);
|
|
850
|
+
expect(semanticResults.length).toBe(2); // doc1 and doc2
|
|
851
|
+
expect(semanticResults[0]!.similarity).toBeGreaterThan(0.9);
|
|
852
|
+
|
|
853
|
+
// Layer 3: Time-based (symbolic)
|
|
854
|
+
const now = new Date();
|
|
855
|
+
const from = new Date(now.getTime() - 60000).toISOString() as Timestamp;
|
|
856
|
+
const to = new Date(now.getTime() + 60000).toISOString() as Timestamp;
|
|
857
|
+
const timeResults = await store.queryByTime(from, to);
|
|
858
|
+
expect(timeResults.length).toBe(3); // All docs
|
|
859
|
+
});
|
|
860
|
+
});
|