@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.
Files changed (178) hide show
  1. package/README.md +86 -23
  2. package/SECURITY.md +254 -0
  3. package/dist/accountability/engine.d.ts +27 -0
  4. package/dist/accountability/engine.d.ts.map +1 -0
  5. package/dist/accountability/engine.js +148 -0
  6. package/dist/accountability/engine.js.map +1 -0
  7. package/dist/accountability/types.d.ts +46 -0
  8. package/dist/accountability/types.d.ts.map +1 -0
  9. package/dist/accountability/types.js +8 -0
  10. package/dist/accountability/types.js.map +1 -0
  11. package/dist/checkpoint/engine.d.ts +2 -2
  12. package/dist/checkpoint/engine.d.ts.map +1 -1
  13. package/dist/checkpoint/engine.js +5 -1
  14. package/dist/checkpoint/engine.js.map +1 -1
  15. package/dist/context/compose.d.ts +62 -0
  16. package/dist/context/compose.d.ts.map +1 -0
  17. package/dist/context/compose.js +286 -0
  18. package/dist/context/compose.js.map +1 -0
  19. package/dist/context/crypto/hash.d.ts +100 -0
  20. package/dist/context/crypto/hash.d.ts.map +1 -0
  21. package/dist/context/crypto/hash.js +248 -0
  22. package/dist/context/crypto/hash.js.map +1 -0
  23. package/dist/context/crypto/hmac.d.ts +80 -0
  24. package/dist/context/crypto/hmac.d.ts.map +1 -0
  25. package/dist/context/crypto/hmac.js +192 -0
  26. package/dist/context/crypto/hmac.js.map +1 -0
  27. package/dist/context/crypto/index.d.ts +7 -0
  28. package/dist/context/crypto/index.d.ts.map +1 -0
  29. package/dist/context/crypto/index.js +7 -0
  30. package/dist/context/crypto/index.js.map +1 -0
  31. package/dist/context/engine-v3.0-backup.d.ts +197 -0
  32. package/dist/context/engine-v3.0-backup.d.ts.map +1 -0
  33. package/dist/context/engine-v3.0-backup.js +392 -0
  34. package/dist/context/engine-v3.0-backup.js.map +1 -0
  35. package/dist/context/engine.d.ts +2 -2
  36. package/dist/context/engine.d.ts.map +1 -1
  37. package/dist/context/engine.js +2 -2
  38. package/dist/context/engine.js.map +1 -1
  39. package/dist/context/fragment.d.ts +99 -0
  40. package/dist/context/fragment.d.ts.map +1 -0
  41. package/dist/context/fragment.js +316 -0
  42. package/dist/context/fragment.js.map +1 -0
  43. package/dist/context/index.d.ts +99 -0
  44. package/dist/context/index.d.ts.map +1 -0
  45. package/dist/context/index.js +180 -0
  46. package/dist/context/index.js.map +1 -0
  47. package/dist/context/provenance.d.ts +80 -0
  48. package/dist/context/provenance.d.ts.map +1 -0
  49. package/dist/context/provenance.js +294 -0
  50. package/dist/context/provenance.js.map +1 -0
  51. package/dist/context/resolve.d.ts +106 -0
  52. package/dist/context/resolve.d.ts.map +1 -0
  53. package/dist/context/resolve.js +440 -0
  54. package/dist/context/resolve.js.map +1 -0
  55. package/dist/context/store.d.ts +156 -0
  56. package/dist/context/store.d.ts.map +1 -0
  57. package/dist/context/store.js +396 -0
  58. package/dist/context/store.js.map +1 -0
  59. package/dist/context/types.d.ts +463 -0
  60. package/dist/context/types.d.ts.map +1 -0
  61. package/dist/context/types.js +94 -0
  62. package/dist/context/types.js.map +1 -0
  63. package/dist/context/utils/atomic.d.ts +76 -0
  64. package/dist/context/utils/atomic.d.ts.map +1 -0
  65. package/dist/context/utils/atomic.js +159 -0
  66. package/dist/context/utils/atomic.js.map +1 -0
  67. package/dist/context/utils/credit.d.ts +65 -0
  68. package/dist/context/utils/credit.d.ts.map +1 -0
  69. package/dist/context/utils/credit.js +164 -0
  70. package/dist/context/utils/credit.js.map +1 -0
  71. package/dist/context/utils/index.d.ts +13 -0
  72. package/dist/context/utils/index.d.ts.map +1 -0
  73. package/dist/context/utils/index.js +13 -0
  74. package/dist/context/utils/index.js.map +1 -0
  75. package/dist/context/utils/utility.d.ts +63 -0
  76. package/dist/context/utils/utility.d.ts.map +1 -0
  77. package/dist/context/utils/utility.js +141 -0
  78. package/dist/context/utils/utility.js.map +1 -0
  79. package/dist/core/commitment.d.ts +26 -3
  80. package/dist/core/commitment.d.ts.map +1 -1
  81. package/dist/core/commitment.js +45 -7
  82. package/dist/core/commitment.js.map +1 -1
  83. package/dist/core/crypto.d.ts +2 -0
  84. package/dist/core/crypto.d.ts.map +1 -1
  85. package/dist/core/crypto.js +12 -0
  86. package/dist/core/crypto.js.map +1 -1
  87. package/dist/index.d.ts +11 -6
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +35 -10
  90. package/dist/index.js.map +1 -1
  91. package/dist/mcca/engine.d.ts.map +1 -1
  92. package/dist/mcca/engine.js +5 -4
  93. package/dist/mcca/engine.js.map +1 -1
  94. package/dist/physics/engine.d.ts +3 -2
  95. package/dist/physics/engine.d.ts.map +1 -1
  96. package/dist/physics/engine.js +37 -3
  97. package/dist/physics/engine.js.map +1 -1
  98. package/dist/provenance/api-handler.d.ts +45 -0
  99. package/dist/provenance/api-handler.d.ts.map +1 -0
  100. package/dist/provenance/api-handler.js +223 -0
  101. package/dist/provenance/api-handler.js.map +1 -0
  102. package/dist/provenance/api-types.d.ts +108 -0
  103. package/dist/provenance/api-types.d.ts.map +1 -0
  104. package/dist/provenance/api-types.js +9 -0
  105. package/dist/provenance/api-types.js.map +1 -0
  106. package/dist/provenance/index.d.ts +6 -0
  107. package/dist/provenance/index.d.ts.map +1 -0
  108. package/dist/provenance/index.js +3 -0
  109. package/dist/provenance/index.js.map +1 -0
  110. package/dist/provenance/provenance-engine.d.ts +63 -0
  111. package/dist/provenance/provenance-engine.d.ts.map +1 -0
  112. package/dist/provenance/provenance-engine.js +311 -0
  113. package/dist/provenance/provenance-engine.js.map +1 -0
  114. package/dist/provenance/types.d.ts +193 -0
  115. package/dist/provenance/types.d.ts.map +1 -0
  116. package/dist/provenance/types.js +9 -0
  117. package/dist/provenance/types.js.map +1 -0
  118. package/dist/tee/engine.d.ts.map +1 -1
  119. package/dist/tee/engine.js +14 -0
  120. package/dist/tee/engine.js.map +1 -1
  121. package/dist/warrant/engine.d.ts +24 -1
  122. package/dist/warrant/engine.d.ts.map +1 -1
  123. package/dist/warrant/engine.js +76 -1
  124. package/dist/warrant/engine.js.map +1 -1
  125. package/dist/zk/engine.d.ts.map +1 -1
  126. package/dist/zk/engine.js +7 -4
  127. package/dist/zk/engine.js.map +1 -1
  128. package/docs/SECURITY-PATCHES.md +170 -0
  129. package/package.json +17 -5
  130. package/src/__tests__/accountability.test.ts +308 -0
  131. package/src/__tests__/l1-verification-modes.test.ts +424 -0
  132. package/src/__tests__/phase1.benchmark.test.ts +94 -0
  133. package/src/__tests__/phase1.test.ts +0 -77
  134. package/src/__tests__/phase2-4.benchmark.test.ts +60 -0
  135. package/src/__tests__/phase2-4.test.ts +1 -52
  136. package/src/__tests__/provenance/api-handler.test.ts +356 -0
  137. package/src/__tests__/provenance/provenance-engine.test.ts +628 -0
  138. package/src/__tests__/sa-2026-008.test.ts +45 -0
  139. package/src/__tests__/sa-2026-009.test.ts +86 -0
  140. package/src/__tests__/sa-2026-010.test.ts +72 -0
  141. package/src/__tests__/sa-2026-012.test.ts +65 -0
  142. package/src/__tests__/sa-2026-nfc.test.ts +40 -0
  143. package/src/__tests__/security.test.ts +786 -0
  144. package/src/accountability/engine.ts +230 -0
  145. package/src/accountability/types.ts +58 -0
  146. package/src/checkpoint/engine.ts +6 -2
  147. package/src/context/__tests__/caret-v0.2.0.test.ts +860 -0
  148. package/src/context/__tests__/integration.test.ts +356 -0
  149. package/src/context/compose.ts +388 -0
  150. package/src/context/crypto/hash.ts +277 -0
  151. package/src/context/crypto/hmac.ts +253 -0
  152. package/src/context/crypto/index.ts +29 -0
  153. package/src/context/engine-v3.0-backup.ts +598 -0
  154. package/src/context/engine.ts +2 -2
  155. package/src/context/fragment.ts +454 -0
  156. package/src/context/index.ts +427 -0
  157. package/src/context/provenance.ts +380 -0
  158. package/src/context/resolve.ts +581 -0
  159. package/src/context/store.ts +503 -0
  160. package/src/context/types.ts +679 -0
  161. package/src/context/utils/atomic.ts +207 -0
  162. package/src/context/utils/credit.ts +224 -0
  163. package/src/context/utils/index.ts +13 -0
  164. package/src/context/utils/utility.ts +200 -0
  165. package/src/core/commitment.ts +130 -68
  166. package/src/core/crypto.ts +13 -0
  167. package/src/index.ts +62 -10
  168. package/src/mcca/engine.ts +5 -4
  169. package/src/physics/engine.ts +42 -5
  170. package/src/provenance/api-handler.ts +248 -0
  171. package/src/provenance/api-types.ts +112 -0
  172. package/src/provenance/index.ts +19 -0
  173. package/src/provenance/provenance-engine.ts +387 -0
  174. package/src/provenance/types.ts +211 -0
  175. package/src/tee/engine.ts +16 -0
  176. package/src/warrant/engine.ts +89 -1
  177. package/src/zk/engine.ts +8 -4
  178. package/tsconfig.json +1 -1
@@ -16,7 +16,7 @@ import { ZKProofsEngine, ClaimBuilder, InsuranceClaimProof, CIRCUIT_CONFIGS } fr
16
16
  import { MCCAEngine, ContextWindowManager, DEFAULT_INFLUENCE_BUDGET } from '../mcca/engine.js';
17
17
  import { generateTimestamp } from '../core/crypto.js';
18
18
 
19
- const TEST_SEAL_KEY = 'test-seal-key-phase-2-4-v3.0.0';
19
+ const TEST_SEAL_KEY = 'test-seal-key-phase-2-4-v3.0.0-x';
20
20
 
21
21
  // ============================================================================
22
22
  // L2 TEE ATTESTATION TESTS
@@ -845,54 +845,3 @@ describe('Three-Layer Attestation Integration', () => {
845
845
  });
846
846
  });
847
847
 
848
- // ============================================================================
849
- // LATENCY SLA TESTS
850
- // ============================================================================
851
-
852
- describe('Latency SLA Compliance', () => {
853
- let commitmentEngine: CommitmentEngine;
854
- let teeEngine: TEEAttestationEngine;
855
-
856
- beforeAll(async () => {
857
- commitmentEngine = new CommitmentEngine();
858
- await commitmentEngine.initialize(TEST_SEAL_KEY);
859
-
860
- teeEngine = new TEEAttestationEngine(commitmentEngine);
861
- await teeEngine.initialize(TEST_SEAL_KEY);
862
- });
863
-
864
- it('L1 commitment should complete in <1ms (P99)', async () => {
865
- const latencies: number[] = [];
866
-
867
- for (let i = 0; i < 100; i++) {
868
- const start = performance.now();
869
- await commitmentEngine.commit({ iteration: i }, `latency-l1-${i}`);
870
- latencies.push(performance.now() - start);
871
- }
872
-
873
- // Sort and get P99
874
- latencies.sort((a, b) => a - b);
875
- const p99 = latencies[98];
876
-
877
- // Note: In Node.js environment, actual latency may vary
878
- // Target is <1ms, we allow 5ms for test stability
879
- expect(p99).toBeLessThan(5);
880
- });
881
-
882
- it('L2 attestation should complete in <10ms (P99)', async () => {
883
- const latencies: number[] = [];
884
-
885
- for (let i = 0; i < 50; i++) {
886
- const start = performance.now();
887
- await teeEngine.attest({ iteration: i }, `latency-l2-${i}`);
888
- latencies.push(performance.now() - start);
889
- }
890
-
891
- // Sort and get P99
892
- latencies.sort((a, b) => a - b);
893
- const p99 = latencies[Math.floor(latencies.length * 0.99)];
894
-
895
- // Target is <10ms, we allow 50ms for test stability
896
- expect(p99).toBeLessThan(50);
897
- });
898
- });
@@ -0,0 +1,356 @@
1
+ /**
2
+ * ProvenanceApiHandler Test Suite
3
+ *
4
+ * Validates the API surface that exposes provenance verification
5
+ * to external parties: model providers, verifiers, and regulators.
6
+ *
7
+ * 20+ tests covering:
8
+ * - Attest endpoint (5 tests)
9
+ * - Verify endpoint (6 tests)
10
+ * - Chain endpoint (5 tests)
11
+ * - Integration / lifecycle (5 tests)
12
+ */
13
+
14
+ import { describe, it, expect, beforeEach } from 'vitest';
15
+ import { ProvenanceEngine } from '../../provenance/provenance-engine.js';
16
+ import { ProvenanceApiHandler } from '../../provenance/api-handler.js';
17
+ import { sha256 } from '../../core/crypto.js';
18
+ import type { AttestRequest, VerifyRequest } from '../../provenance/api-types.js';
19
+
20
+ // ============================================================================
21
+ // Fixtures
22
+ // ============================================================================
23
+
24
+ function makeAttestRequest(overrides?: Partial<AttestRequest>): AttestRequest {
25
+ return {
26
+ model: {
27
+ name: 'claude-opus-4.6',
28
+ version: '4.6.0',
29
+ manifestHash: 'abc123def456',
30
+ provider: 'anthropic',
31
+ },
32
+ constraints: {
33
+ safetyTier: 'high',
34
+ authorizedDomains: ['code_generation', 'analysis'],
35
+ excludedDomains: ['weapons'],
36
+ maxContextWindow: 200000,
37
+ reasoningEnabled: true,
38
+ },
39
+ deployment: {
40
+ environment: 'api',
41
+ region: 'us-east-1',
42
+ tenantId: 'longarc-studios',
43
+ },
44
+ ...overrides,
45
+ };
46
+ }
47
+
48
+ function makeVerifyRequest(overrides?: Partial<VerifyRequest>): VerifyRequest {
49
+ return {
50
+ modelName: 'claude-opus-4.6',
51
+ modelVersion: '4.6.0',
52
+ queryType: 'full_chain',
53
+ ...overrides,
54
+ };
55
+ }
56
+
57
+ // ============================================================================
58
+ // Attest Endpoint
59
+ // ============================================================================
60
+
61
+ describe('ProvenanceApiHandler', () => {
62
+ let engine: ProvenanceEngine;
63
+ let handler: ProvenanceApiHandler;
64
+
65
+ beforeEach(() => {
66
+ engine = new ProvenanceEngine();
67
+ handler = new ProvenanceApiHandler(engine);
68
+ });
69
+
70
+ describe('handleAttest', () => {
71
+ it('valid request returns 201 with attestation ID', async () => {
72
+ const result = await handler.handleAttest(makeAttestRequest());
73
+
74
+ expect(result.status).toBe(201);
75
+ expect(result.body.status).toBe('created');
76
+ expect(result.body.attestationId).toBeTruthy();
77
+ expect(result.body.attestationId).toMatch(/^[a-f0-9]{64}$/);
78
+ });
79
+
80
+ it('response includes L1 hash and timestamp', async () => {
81
+ const result = await handler.handleAttest(makeAttestRequest());
82
+
83
+ expect(result.body.l1Hash).toBeTruthy();
84
+ expect(result.body.l1Hash).toMatch(/^[a-f0-9]{64}$/);
85
+ expect(result.body.timestamp).toBeTruthy();
86
+ expect(result.body.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/);
87
+ });
88
+
89
+ it('missing model.name returns 400', async () => {
90
+ const req = makeAttestRequest();
91
+ req.model.name = '';
92
+
93
+ const result = await handler.handleAttest(req);
94
+
95
+ expect(result.status).toBe(400);
96
+ expect(result.body.status).toBe('error');
97
+ expect(result.body.error).toContain('name');
98
+ });
99
+
100
+ it('missing model.provider returns 400', async () => {
101
+ const req = makeAttestRequest();
102
+ req.model.provider = '';
103
+
104
+ const result = await handler.handleAttest(req);
105
+
106
+ expect(result.status).toBe(400);
107
+ expect(result.body.status).toBe('error');
108
+ expect(result.body.error).toContain('provider');
109
+ });
110
+
111
+ it('duplicate attestation returns 409', async () => {
112
+ await handler.handleAttest(makeAttestRequest());
113
+ const result = await handler.handleAttest(makeAttestRequest());
114
+
115
+ expect(result.status).toBe(409);
116
+ expect(result.body.status).toBe('error');
117
+ expect(result.body.error).toContain('already exists');
118
+ });
119
+ });
120
+
121
+ // ============================================================================
122
+ // Verify Endpoint
123
+ // ============================================================================
124
+
125
+ describe('handleVerify', () => {
126
+ beforeEach(async () => {
127
+ // Seed a model with a full provenance chain
128
+ const attestation = await engine.createIdentityAttestation(
129
+ { name: 'claude-opus-4.6', version: '4.6.0', manifestHash: 'abc', provider: 'anthropic' },
130
+ {
131
+ safetyTier: 'high',
132
+ authorizedDomains: ['code_generation'],
133
+ excludedDomains: ['weapons'],
134
+ maxContextWindow: 200000,
135
+ reasoningEnabled: true,
136
+ custom: {},
137
+ },
138
+ { environment: 'api', region: 'us-east-1' }
139
+ );
140
+ const warrants = [await sha256('warrant-0'), await sha256('warrant-1')];
141
+ const glossEntries = [
142
+ { id: 'g-0', type: 'action', agentId: 'a-1', sessionId: 's-1', timestamp: new Date().toISOString() },
143
+ { id: 'g-1', type: 'action', agentId: 'a-1', sessionId: 's-1', timestamp: new Date().toISOString() },
144
+ { id: 'g-2', type: 'action', agentId: 'a-1', sessionId: 's-2', timestamp: new Date().toISOString() },
145
+ ];
146
+ await engine.buildProvenanceChain(attestation, warrants, glossEntries);
147
+ });
148
+
149
+ it('known model with full chain returns verified', async () => {
150
+ const result = await handler.handleVerify(makeVerifyRequest());
151
+
152
+ expect(result.status).toBe(200);
153
+ expect(result.body.status).toBe('verified');
154
+ expect(result.body.chain.isComplete).toBe(true);
155
+ });
156
+
157
+ it('unknown model returns unverified with 404', async () => {
158
+ const result = await handler.handleVerify(
159
+ makeVerifyRequest({ modelName: 'unknown-model', modelVersion: '1.0.0' })
160
+ );
161
+
162
+ expect(result.status).toBe(404);
163
+ expect(result.body.status).toBe('unverified');
164
+ expect(result.body.chain.isComplete).toBe(false);
165
+ });
166
+
167
+ it('missing modelName returns 400', async () => {
168
+ const result = await handler.handleVerify(
169
+ makeVerifyRequest({ modelName: '' })
170
+ );
171
+
172
+ expect(result.status).toBe(400);
173
+ expect(result.body.status).toBe('error');
174
+ expect(result.body.error).toContain('modelName');
175
+ });
176
+
177
+ it('query type identity returns identity data', async () => {
178
+ const result = await handler.handleVerify(
179
+ makeVerifyRequest({ queryType: 'identity' })
180
+ );
181
+
182
+ expect(result.status).toBe(200);
183
+ expect(result.body.chain.isComplete).toBe(true);
184
+ });
185
+
186
+ it('ZK proof requested returns proof and verification key', async () => {
187
+ const result = await handler.handleVerify(
188
+ makeVerifyRequest({ generateZkProof: true })
189
+ );
190
+
191
+ expect(result.status).toBe(200);
192
+ expect(result.body.zkProof).toBeTruthy();
193
+ expect(result.body.zkProof!.claim).toBeTruthy();
194
+ expect(result.body.zkProof!.proof).toMatch(/^[a-f0-9]{64}$/);
195
+ expect(result.body.zkProof!.verificationKey).toMatch(/^[a-f0-9]{64}$/);
196
+ });
197
+
198
+ it('hardware attestation requested includes L2 placeholder', async () => {
199
+ const result = await handler.handleVerify(
200
+ makeVerifyRequest({ requireHardwareAttestation: true })
201
+ );
202
+
203
+ expect(result.status).toBe(200);
204
+ // L2 placeholder is on the chain identity, reflected in the response
205
+ expect(result.body.status).toBe('verified');
206
+ });
207
+ });
208
+
209
+ // ============================================================================
210
+ // Chain Endpoint
211
+ // ============================================================================
212
+
213
+ describe('handleGetChain', () => {
214
+ beforeEach(async () => {
215
+ const attestation = await engine.createIdentityAttestation(
216
+ { name: 'claude-opus-4.6', version: '4.6.0', manifestHash: 'abc', provider: 'anthropic' },
217
+ {
218
+ safetyTier: 'high',
219
+ authorizedDomains: ['code_generation'],
220
+ excludedDomains: ['weapons'],
221
+ maxContextWindow: 200000,
222
+ reasoningEnabled: true,
223
+ custom: {},
224
+ },
225
+ { environment: 'api', region: 'us-east-1' }
226
+ );
227
+ const warrants = [await sha256('warrant-0'), await sha256('warrant-1'), await sha256('warrant-2')];
228
+ const glossEntries = [
229
+ { id: 'g-0', type: 'action', agentId: 'a-1', sessionId: 's-1', timestamp: new Date().toISOString() },
230
+ { id: 'g-1', type: 'action', agentId: 'a-1', sessionId: 's-2', timestamp: new Date().toISOString() },
231
+ ];
232
+ await engine.buildProvenanceChain(attestation, warrants, glossEntries);
233
+ });
234
+
235
+ it('known model returns full chain response', async () => {
236
+ const result = await handler.handleGetChain('claude-opus-4.6:4.6.0');
237
+
238
+ expect(result.status).toBe(200);
239
+ expect(result.body.modelId).toBe('claude-opus-4.6:4.6.0');
240
+ expect(result.body.identity.name).toBe('claude-opus-4.6');
241
+ expect(result.body.identity.provider).toBe('anthropic');
242
+ });
243
+
244
+ it('unknown model returns 404', async () => {
245
+ const result = await handler.handleGetChain('nonexistent:1.0.0');
246
+
247
+ expect(result.status).toBe(404);
248
+ });
249
+
250
+ it('response includes warrant summary', async () => {
251
+ const result = await handler.handleGetChain('claude-opus-4.6:4.6.0');
252
+
253
+ expect(result.body.warrants.total).toBe(3);
254
+ expect(result.body.warrants.active).toBe(3);
255
+ expect(result.body.warrants.chainHash).toBeTruthy();
256
+ });
257
+
258
+ it('response includes behavioral summary', async () => {
259
+ const result = await handler.handleGetChain('claude-opus-4.6:4.6.0');
260
+
261
+ expect(result.body.behavior.totalSessions).toBe(2);
262
+ expect(result.body.behavior.totalActions).toBe(2);
263
+ expect(result.body.behavior.violations).toBe(0);
264
+ });
265
+
266
+ it('response includes verdict', async () => {
267
+ const result = await handler.handleGetChain('claude-opus-4.6:4.6.0');
268
+
269
+ expect(result.body.verdict.isComplete).toBe(true);
270
+ expect(result.body.verdict.confidence).toBeGreaterThan(0.5);
271
+ expect(result.body.verdict.assessment).toBeTruthy();
272
+ });
273
+ });
274
+
275
+ // ============================================================================
276
+ // Integration / Lifecycle
277
+ // ============================================================================
278
+
279
+ describe('Integration', () => {
280
+ it('attest then verify then chain: full lifecycle', async () => {
281
+ // Step 1: Attest
282
+ const attestResult = await handler.handleAttest(makeAttestRequest());
283
+ expect(attestResult.status).toBe(201);
284
+
285
+ // Step 2: Verify (engine has identity but no chain yet -- will build minimal)
286
+ const verifyResult = await handler.handleVerify(makeVerifyRequest());
287
+ expect(verifyResult.status).toBe(200);
288
+
289
+ // Step 3: Get chain
290
+ const chainResult = await handler.handleGetChain('claude-opus-4.6:4.6.0');
291
+ expect(chainResult.status).toBe(200);
292
+ expect(chainResult.body.identity.l1Hash).toBe(attestResult.body.l1Hash);
293
+ });
294
+
295
+ it('attest clean model then verify returns high confidence', async () => {
296
+ // Attest via API
297
+ await handler.handleAttest(makeAttestRequest());
298
+
299
+ // Build a chain with good history directly on engine
300
+ const identity = engine.getIdentity('claude-opus-4.6', '4.6.0')!;
301
+ const warrants = [await sha256('w-0'), await sha256('w-1')];
302
+ const entries = Array.from({ length: 10 }, (_, i) => ({
303
+ id: `g-${i}`, type: 'action', agentId: 'a-1',
304
+ sessionId: `s-${i % 3}`, timestamp: new Date().toISOString(),
305
+ }));
306
+ await engine.buildProvenanceChain(identity, warrants, entries);
307
+
308
+ const result = await handler.handleVerify(makeVerifyRequest());
309
+ expect(result.body.chain.confidence).toBeGreaterThanOrEqual(0.9);
310
+ expect(result.body.chain.flags).toEqual([]);
311
+ });
312
+
313
+ it('query model with no attestation returns unverified', async () => {
314
+ const result = await handler.handleVerify(
315
+ makeVerifyRequest({ modelName: 'phantom-model', modelVersion: '0.0.1' })
316
+ );
317
+
318
+ expect(result.status).toBe(404);
319
+ expect(result.body.status).toBe('unverified');
320
+ expect(result.body.chain.confidence).toBe(0);
321
+ });
322
+
323
+ it('two models attested, each returns correct chain', async () => {
324
+ // Attest model A
325
+ await handler.handleAttest(makeAttestRequest());
326
+
327
+ // Attest model B
328
+ await handler.handleAttest(makeAttestRequest({
329
+ model: { name: 'gpt-5', version: '5.0.0', provider: 'openai' },
330
+ deployment: { environment: 'enterprise' },
331
+ }));
332
+
333
+ const chainA = await handler.handleGetChain('claude-opus-4.6:4.6.0');
334
+ const chainB = await handler.handleGetChain('gpt-5:5.0.0');
335
+
336
+ expect(chainA.body.identity.provider).toBe('anthropic');
337
+ expect(chainB.body.identity.provider).toBe('openai');
338
+ expect(chainA.body.identity.l1Hash).not.toBe(chainB.body.identity.l1Hash);
339
+ });
340
+
341
+ it('verify with time window passes through to engine', async () => {
342
+ await handler.handleAttest(makeAttestRequest());
343
+
344
+ const result = await handler.handleVerify(makeVerifyRequest({
345
+ timeWindow: {
346
+ start: '2026-01-01T00:00:00Z',
347
+ end: '2026-12-31T23:59:59Z',
348
+ },
349
+ }));
350
+
351
+ // Time window doesn't change outcome for in-memory store,
352
+ // but the request should succeed without error
353
+ expect(result.status).toBe(200);
354
+ });
355
+ });
356
+ });