@vorionsys/cognigate 1.0.0

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/index.js ADDED
@@ -0,0 +1,477 @@
1
+ // src/types.ts
2
+ import { z } from "zod";
3
+ var TrustTier = /* @__PURE__ */ ((TrustTier2) => {
4
+ TrustTier2[TrustTier2["T0_SANDBOX"] = 0] = "T0_SANDBOX";
5
+ TrustTier2[TrustTier2["T1_OBSERVED"] = 1] = "T1_OBSERVED";
6
+ TrustTier2[TrustTier2["T2_PROVISIONAL"] = 2] = "T2_PROVISIONAL";
7
+ TrustTier2[TrustTier2["T3_VERIFIED"] = 3] = "T3_VERIFIED";
8
+ TrustTier2[TrustTier2["T4_OPERATIONAL"] = 4] = "T4_OPERATIONAL";
9
+ TrustTier2[TrustTier2["T5_TRUSTED"] = 5] = "T5_TRUSTED";
10
+ TrustTier2[TrustTier2["T6_CERTIFIED"] = 6] = "T6_CERTIFIED";
11
+ TrustTier2[TrustTier2["T7_AUTONOMOUS"] = 7] = "T7_AUTONOMOUS";
12
+ return TrustTier2;
13
+ })(TrustTier || {});
14
+ var TIER_THRESHOLDS = {
15
+ [0 /* T0_SANDBOX */]: { min: 0, max: 199, name: "Sandbox" },
16
+ [1 /* T1_OBSERVED */]: { min: 200, max: 349, name: "Observed" },
17
+ [2 /* T2_PROVISIONAL */]: { min: 350, max: 499, name: "Provisional" },
18
+ [3 /* T3_VERIFIED */]: { min: 500, max: 649, name: "Verified" },
19
+ [4 /* T4_OPERATIONAL */]: { min: 650, max: 799, name: "Operational" },
20
+ [5 /* T5_TRUSTED */]: { min: 800, max: 875, name: "Trusted" },
21
+ [6 /* T6_CERTIFIED */]: { min: 876, max: 949, name: "Certified" },
22
+ [7 /* T7_AUTONOMOUS */]: { min: 950, max: 1e3, name: "Autonomous" }
23
+ };
24
+ var TrustStatusSchema = z.object({
25
+ entityId: z.string(),
26
+ trustScore: z.number().min(0).max(1e3),
27
+ trustTier: z.nativeEnum(TrustTier),
28
+ tierName: z.string(),
29
+ capabilities: z.array(z.string()),
30
+ factorScores: z.record(z.string(), z.number()),
31
+ lastEvaluated: z.coerce.date(),
32
+ compliant: z.boolean(),
33
+ warnings: z.array(z.string())
34
+ });
35
+ var GovernanceResultSchema = z.object({
36
+ decision: z.enum(["ALLOW", "DENY", "ESCALATE", "DEGRADE"]),
37
+ trustScore: z.number(),
38
+ trustTier: z.nativeEnum(TrustTier),
39
+ grantedCapabilities: z.array(z.string()),
40
+ deniedCapabilities: z.array(z.string()),
41
+ reasoning: z.string(),
42
+ constraints: z.record(z.string(), z.unknown()).optional(),
43
+ proofId: z.string().optional(),
44
+ timestamp: z.coerce.date()
45
+ });
46
+ var ProofRecordSchema = z.object({
47
+ id: z.string(),
48
+ entityId: z.string(),
49
+ intentId: z.string(),
50
+ decision: z.enum(["ALLOW", "DENY", "ESCALATE", "DEGRADE"]),
51
+ action: z.string(),
52
+ outcome: z.enum(["SUCCESS", "FAILURE", "PARTIAL", "PENDING"]),
53
+ trustScoreBefore: z.number(),
54
+ trustScoreAfter: z.number(),
55
+ timestamp: z.coerce.date(),
56
+ hash: z.string(),
57
+ previousHash: z.string(),
58
+ metadata: z.record(z.string(), z.unknown()).optional()
59
+ });
60
+ var AgentSchema = z.object({
61
+ id: z.string(),
62
+ name: z.string(),
63
+ description: z.string(),
64
+ ownerId: z.string(),
65
+ trustScore: z.number(),
66
+ trustTier: z.nativeEnum(TrustTier),
67
+ status: z.enum(["ACTIVE", "PAUSED", "SUSPENDED", "TERMINATED"]),
68
+ capabilities: z.array(z.string()),
69
+ executions: z.number(),
70
+ successRate: z.number(),
71
+ createdAt: z.coerce.date(),
72
+ updatedAt: z.coerce.date(),
73
+ metadata: z.record(z.string(), z.unknown()).optional()
74
+ });
75
+
76
+ // src/client.ts
77
+ var DEFAULT_BASE_URL = "https://cognigate.dev/v1";
78
+ var DEFAULT_TIMEOUT = 3e4;
79
+ var DEFAULT_RETRIES = 3;
80
+ var CognigateError = class extends Error {
81
+ constructor(message, code, status, details) {
82
+ super(message);
83
+ this.code = code;
84
+ this.status = status;
85
+ this.details = details;
86
+ this.name = "CognigateError";
87
+ }
88
+ };
89
+ var Cognigate = class {
90
+ config;
91
+ agents;
92
+ trust;
93
+ governance;
94
+ proofs;
95
+ constructor(config) {
96
+ if (!config.apiKey) {
97
+ throw new CognigateError("API key is required", "MISSING_API_KEY");
98
+ }
99
+ this.config = {
100
+ apiKey: config.apiKey,
101
+ baseUrl: config.baseUrl || DEFAULT_BASE_URL,
102
+ timeout: config.timeout || DEFAULT_TIMEOUT,
103
+ retries: config.retries || DEFAULT_RETRIES,
104
+ debug: config.debug || false,
105
+ webhookSecret: config.webhookSecret
106
+ };
107
+ this.agents = new AgentsClient(this);
108
+ this.trust = new TrustClient(this);
109
+ this.governance = new GovernanceClient(this);
110
+ this.proofs = new ProofsClient(this);
111
+ }
112
+ /**
113
+ * Make an authenticated request to the Cognigate API
114
+ */
115
+ async request(method, path, body) {
116
+ const url = `${this.config.baseUrl}${path}`;
117
+ const headers = {
118
+ "Authorization": `Bearer ${this.config.apiKey}`,
119
+ "Content-Type": "application/json",
120
+ "X-SDK-Version": "1.0.0",
121
+ "X-SDK-Language": "typescript"
122
+ };
123
+ let lastError = null;
124
+ for (let attempt = 0; attempt < this.config.retries; attempt++) {
125
+ try {
126
+ const controller = new AbortController();
127
+ const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
128
+ const response = await fetch(url, {
129
+ method,
130
+ headers,
131
+ body: body ? JSON.stringify(body) : void 0,
132
+ signal: controller.signal
133
+ });
134
+ clearTimeout(timeoutId);
135
+ if (this.config.debug) {
136
+ console.log(`[Cognigate] ${method} ${path} -> ${response.status}`);
137
+ }
138
+ if (!response.ok) {
139
+ const errorData = await response.json().catch(() => ({}));
140
+ throw new CognigateError(
141
+ errorData.message || `Request failed with status ${response.status}`,
142
+ errorData.code || "REQUEST_FAILED",
143
+ response.status,
144
+ errorData.details
145
+ );
146
+ }
147
+ const data = await response.json();
148
+ return data;
149
+ } catch (error) {
150
+ lastError = error;
151
+ if (error instanceof CognigateError && error.status && error.status < 500) {
152
+ throw error;
153
+ }
154
+ if (attempt < this.config.retries - 1) {
155
+ const delay = Math.pow(2, attempt) * 1e3;
156
+ await new Promise((resolve) => setTimeout(resolve, delay));
157
+ }
158
+ }
159
+ }
160
+ throw lastError || new CognigateError("Request failed", "UNKNOWN_ERROR");
161
+ }
162
+ /**
163
+ * Check API health
164
+ */
165
+ async health() {
166
+ return this.request("GET", "/health");
167
+ }
168
+ /**
169
+ * Get tier from trust score
170
+ */
171
+ static getTierFromScore(score) {
172
+ if (score >= 950) return 7 /* T7_AUTONOMOUS */;
173
+ if (score >= 876) return 6 /* T6_CERTIFIED */;
174
+ if (score >= 800) return 5 /* T5_TRUSTED */;
175
+ if (score >= 650) return 4 /* T4_OPERATIONAL */;
176
+ if (score >= 500) return 3 /* T3_VERIFIED */;
177
+ if (score >= 350) return 2 /* T2_PROVISIONAL */;
178
+ if (score >= 200) return 1 /* T1_OBSERVED */;
179
+ return 0 /* T0_SANDBOX */;
180
+ }
181
+ /**
182
+ * Get tier name
183
+ */
184
+ static getTierName(tier) {
185
+ return TIER_THRESHOLDS[tier].name;
186
+ }
187
+ /**
188
+ * Get tier thresholds
189
+ */
190
+ static getTierThresholds(tier) {
191
+ return TIER_THRESHOLDS[tier];
192
+ }
193
+ };
194
+ var AgentsClient = class {
195
+ constructor(client) {
196
+ this.client = client;
197
+ }
198
+ /**
199
+ * List all agents
200
+ */
201
+ async list(params) {
202
+ const query = new URLSearchParams();
203
+ if (params?.page) query.set("page", params.page.toString());
204
+ if (params?.pageSize) query.set("pageSize", params.pageSize.toString());
205
+ if (params?.status) query.set("status", params.status);
206
+ const queryString = query.toString();
207
+ const path = `/agents${queryString ? `?${queryString}` : ""}`;
208
+ return this.client.request("GET", path);
209
+ }
210
+ /**
211
+ * Get a specific agent
212
+ */
213
+ async get(agentId) {
214
+ const response = await this.client.request("GET", `/agents/${agentId}`);
215
+ return AgentSchema.parse(response);
216
+ }
217
+ /**
218
+ * Create a new agent
219
+ */
220
+ async create(data) {
221
+ const response = await this.client.request("POST", "/agents", data);
222
+ return AgentSchema.parse(response);
223
+ }
224
+ /**
225
+ * Update an agent
226
+ */
227
+ async update(agentId, data) {
228
+ const response = await this.client.request("PATCH", `/agents/${agentId}`, data);
229
+ return AgentSchema.parse(response);
230
+ }
231
+ /**
232
+ * Delete an agent
233
+ */
234
+ async delete(agentId) {
235
+ await this.client.request("DELETE", `/agents/${agentId}`);
236
+ }
237
+ /**
238
+ * Pause an agent
239
+ */
240
+ async pause(agentId) {
241
+ return this.update(agentId, { status: "PAUSED" });
242
+ }
243
+ /**
244
+ * Resume an agent
245
+ */
246
+ async resume(agentId) {
247
+ return this.update(agentId, { status: "ACTIVE" });
248
+ }
249
+ };
250
+ var TrustClient = class {
251
+ constructor(client) {
252
+ this.client = client;
253
+ }
254
+ /**
255
+ * Get trust status for an entity
256
+ */
257
+ async getStatus(entityId) {
258
+ const response = await this.client.request("GET", `/trust/${entityId}`);
259
+ return TrustStatusSchema.parse(response);
260
+ }
261
+ /**
262
+ * Get trust history
263
+ */
264
+ async getHistory(entityId, params) {
265
+ const query = new URLSearchParams();
266
+ if (params?.from) query.set("from", params.from.toISOString());
267
+ if (params?.to) query.set("to", params.to.toISOString());
268
+ if (params?.limit) query.set("limit", params.limit.toString());
269
+ const queryString = query.toString();
270
+ const path = `/trust/${entityId}/history${queryString ? `?${queryString}` : ""}`;
271
+ return this.client.request("GET", path);
272
+ }
273
+ /**
274
+ * Submit an outcome to update trust score
275
+ */
276
+ async submitOutcome(entityId, proofId, outcome) {
277
+ const response = await this.client.request(
278
+ "POST",
279
+ `/trust/${entityId}/outcome`,
280
+ { proofId, ...outcome }
281
+ );
282
+ return TrustStatusSchema.parse(response);
283
+ }
284
+ };
285
+ var GovernanceClient = class {
286
+ constructor(client) {
287
+ this.client = client;
288
+ }
289
+ /**
290
+ * Parse user intent into structured format
291
+ */
292
+ async parseIntent(entityId, rawInput) {
293
+ return this.client.request("POST", "/governance/parse", {
294
+ entityId,
295
+ rawInput
296
+ });
297
+ }
298
+ /**
299
+ * Enforce governance rules on an intent
300
+ */
301
+ async enforce(intent) {
302
+ const response = await this.client.request(
303
+ "POST",
304
+ "/governance/enforce",
305
+ intent
306
+ );
307
+ return GovernanceResultSchema.parse(response);
308
+ }
309
+ /**
310
+ * Convenience method: parse and enforce in one call
311
+ */
312
+ async evaluate(entityId, rawInput) {
313
+ const parseResult = await this.parseIntent(entityId, rawInput);
314
+ const result = await this.enforce(parseResult.intent);
315
+ return {
316
+ intent: parseResult.intent,
317
+ result
318
+ };
319
+ }
320
+ /**
321
+ * Check if an action is allowed without creating a proof record
322
+ */
323
+ async canPerform(entityId, action, capabilities) {
324
+ return this.client.request("POST", "/governance/check", {
325
+ entityId,
326
+ action,
327
+ capabilities
328
+ });
329
+ }
330
+ };
331
+ var ProofsClient = class {
332
+ constructor(client) {
333
+ this.client = client;
334
+ }
335
+ /**
336
+ * Get a specific proof record
337
+ */
338
+ async get(proofId) {
339
+ const response = await this.client.request("GET", `/proofs/${proofId}`);
340
+ return ProofRecordSchema.parse(response);
341
+ }
342
+ /**
343
+ * List proof records for an entity
344
+ */
345
+ async list(entityId, params) {
346
+ const query = new URLSearchParams();
347
+ query.set("entityId", entityId);
348
+ if (params?.page) query.set("page", params.page.toString());
349
+ if (params?.pageSize) query.set("pageSize", params.pageSize.toString());
350
+ if (params?.from) query.set("from", params.from.toISOString());
351
+ if (params?.to) query.set("to", params.to.toISOString());
352
+ if (params?.outcome) query.set("outcome", params.outcome);
353
+ return this.client.request("GET", `/proofs?${query.toString()}`);
354
+ }
355
+ /**
356
+ * Get proof chain statistics
357
+ */
358
+ async getStats(entityId) {
359
+ return this.client.request("GET", `/proofs/stats/${entityId}`);
360
+ }
361
+ /**
362
+ * Verify proof chain integrity
363
+ */
364
+ async verify(entityId) {
365
+ return this.client.request("POST", `/proofs/verify/${entityId}`);
366
+ }
367
+ };
368
+
369
+ // src/webhooks.ts
370
+ async function verifyWebhookSignature(payload, signature, secret) {
371
+ const encoder = new TextEncoder();
372
+ const data = encoder.encode(payload);
373
+ const key = await crypto.subtle.importKey(
374
+ "raw",
375
+ encoder.encode(secret),
376
+ { name: "HMAC", hash: "SHA-256" },
377
+ false,
378
+ ["sign"]
379
+ );
380
+ const signatureBuffer = await crypto.subtle.sign("HMAC", key, data);
381
+ const expectedSignature = bufferToHex(signatureBuffer);
382
+ return timingSafeEqual(signature, expectedSignature);
383
+ }
384
+ function parseWebhookPayload(body, signature, secret) {
385
+ return new Promise(async (resolve, reject) => {
386
+ const isValid = await verifyWebhookSignature(body, signature, secret);
387
+ if (!isValid) {
388
+ reject(new Error("Invalid webhook signature"));
389
+ return;
390
+ }
391
+ try {
392
+ const event = JSON.parse(body);
393
+ event.timestamp = new Date(event.timestamp);
394
+ resolve(event);
395
+ } catch (error) {
396
+ reject(new Error("Invalid webhook payload"));
397
+ }
398
+ });
399
+ }
400
+ var WebhookRouter = class {
401
+ handlers = /* @__PURE__ */ new Map();
402
+ /**
403
+ * Register a handler for a specific event type
404
+ */
405
+ on(type, handler) {
406
+ const existing = this.handlers.get(type) || [];
407
+ existing.push(handler);
408
+ this.handlers.set(type, existing);
409
+ return this;
410
+ }
411
+ /**
412
+ * Register a handler for all events
413
+ */
414
+ onAll(handler) {
415
+ const existing = this.handlers.get("*") || [];
416
+ existing.push(handler);
417
+ this.handlers.set("*", existing);
418
+ return this;
419
+ }
420
+ /**
421
+ * Handle a webhook event
422
+ */
423
+ async handle(event) {
424
+ const typeHandlers = this.handlers.get(event.type) || [];
425
+ const allHandlers = this.handlers.get("*") || [];
426
+ const handlers = [...typeHandlers, ...allHandlers];
427
+ for (const handler of handlers) {
428
+ await handler(event);
429
+ }
430
+ }
431
+ /**
432
+ * Create an Express/Connect compatible middleware
433
+ */
434
+ middleware(secret) {
435
+ return async (req, res, _next) => {
436
+ try {
437
+ const signature = req.headers["x-cognigate-signature"];
438
+ const body = typeof req.body === "string" ? req.body : JSON.stringify(req.body);
439
+ const event = await parseWebhookPayload(body, signature, secret);
440
+ await this.handle(event);
441
+ res.status(200).json({ received: true });
442
+ } catch (error) {
443
+ res.status(400).json({ error: error.message });
444
+ }
445
+ };
446
+ }
447
+ };
448
+ function bufferToHex(buffer) {
449
+ return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
450
+ }
451
+ function timingSafeEqual(a, b) {
452
+ if (a.length !== b.length) {
453
+ return false;
454
+ }
455
+ let result = 0;
456
+ for (let i = 0; i < a.length; i++) {
457
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
458
+ }
459
+ return result === 0;
460
+ }
461
+
462
+ // src/index.ts
463
+ import { z as z2 } from "zod";
464
+ export {
465
+ AgentSchema,
466
+ Cognigate,
467
+ CognigateError,
468
+ GovernanceResultSchema,
469
+ ProofRecordSchema,
470
+ TIER_THRESHOLDS,
471
+ TrustStatusSchema,
472
+ TrustTier,
473
+ WebhookRouter,
474
+ parseWebhookPayload,
475
+ verifyWebhookSignature,
476
+ z2 as z
477
+ };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@vorionsys/cognigate",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript SDK for the Cognigate AI governance API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup src/index.ts --format esm,cjs --dts",
17
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
18
+ "typecheck": "tsc --noEmit",
19
+ "test": "vitest",
20
+ "lint": "eslint src --ext .ts"
21
+ },
22
+ "keywords": [
23
+ "ai",
24
+ "governance",
25
+ "trust",
26
+ "agents",
27
+ "cognigate",
28
+ "basis",
29
+ "vorion"
30
+ ],
31
+ "author": "Vorion <team@vorion.dev>",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/vorion-dev/vorion.git",
36
+ "directory": "packages/cognigate"
37
+ },
38
+ "homepage": "https://cognigate.dev",
39
+ "dependencies": {
40
+ "zod": "^3.24.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.7.0",
46
+ "vitest": "^2.0.0"
47
+ },
48
+ "peerDependencies": {
49
+ "typescript": ">=5.0.0"
50
+ },
51
+ "engines": {
52
+ "node": ">=18.0.0"
53
+ }
54
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Cognigate SDK Tests
3
+ */
4
+
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
6
+ import { Cognigate, CognigateError } from '../client.js';
7
+ import { TrustTier, TIER_THRESHOLDS } from '../types.js';
8
+
9
+ describe('Cognigate', () => {
10
+ describe('constructor', () => {
11
+ it('throws error when API key is missing', () => {
12
+ expect(() => new Cognigate({ apiKey: '' })).toThrow(CognigateError);
13
+ expect(() => new Cognigate({ apiKey: '' })).toThrow('API key is required');
14
+ });
15
+
16
+ it('creates client with valid API key', () => {
17
+ const client = new Cognigate({ apiKey: 'test-key' });
18
+ expect(client).toBeInstanceOf(Cognigate);
19
+ expect(client.agents).toBeDefined();
20
+ expect(client.trust).toBeDefined();
21
+ expect(client.governance).toBeDefined();
22
+ expect(client.proofs).toBeDefined();
23
+ });
24
+
25
+ it('uses default config values', () => {
26
+ const client = new Cognigate({ apiKey: 'test-key' });
27
+ // Check that sub-clients are properly initialized
28
+ expect(client.agents).toBeDefined();
29
+ });
30
+
31
+ it('accepts custom config values', () => {
32
+ const client = new Cognigate({
33
+ apiKey: 'test-key',
34
+ baseUrl: 'https://custom.api.com',
35
+ timeout: 60000,
36
+ retries: 5,
37
+ debug: true,
38
+ });
39
+ expect(client).toBeInstanceOf(Cognigate);
40
+ });
41
+ });
42
+
43
+ describe('getTierFromScore', () => {
44
+ it('returns T0_SANDBOX for scores 0-199', () => {
45
+ expect(Cognigate.getTierFromScore(0)).toBe(TrustTier.T0_SANDBOX);
46
+ expect(Cognigate.getTierFromScore(100)).toBe(TrustTier.T0_SANDBOX);
47
+ expect(Cognigate.getTierFromScore(199)).toBe(TrustTier.T0_SANDBOX);
48
+ });
49
+
50
+ it('returns T1_OBSERVED for scores 200-349', () => {
51
+ expect(Cognigate.getTierFromScore(200)).toBe(TrustTier.T1_OBSERVED);
52
+ expect(Cognigate.getTierFromScore(275)).toBe(TrustTier.T1_OBSERVED);
53
+ expect(Cognigate.getTierFromScore(349)).toBe(TrustTier.T1_OBSERVED);
54
+ });
55
+
56
+ it('returns T2_PROVISIONAL for scores 350-499', () => {
57
+ expect(Cognigate.getTierFromScore(350)).toBe(TrustTier.T2_PROVISIONAL);
58
+ expect(Cognigate.getTierFromScore(425)).toBe(TrustTier.T2_PROVISIONAL);
59
+ expect(Cognigate.getTierFromScore(499)).toBe(TrustTier.T2_PROVISIONAL);
60
+ });
61
+
62
+ it('returns T3_VERIFIED for scores 500-649', () => {
63
+ expect(Cognigate.getTierFromScore(500)).toBe(TrustTier.T3_VERIFIED);
64
+ expect(Cognigate.getTierFromScore(575)).toBe(TrustTier.T3_VERIFIED);
65
+ expect(Cognigate.getTierFromScore(649)).toBe(TrustTier.T3_VERIFIED);
66
+ });
67
+
68
+ it('returns T4_OPERATIONAL for scores 650-799', () => {
69
+ expect(Cognigate.getTierFromScore(650)).toBe(TrustTier.T4_OPERATIONAL);
70
+ expect(Cognigate.getTierFromScore(725)).toBe(TrustTier.T4_OPERATIONAL);
71
+ expect(Cognigate.getTierFromScore(799)).toBe(TrustTier.T4_OPERATIONAL);
72
+ });
73
+
74
+ it('returns T5_TRUSTED for scores 800-875', () => {
75
+ expect(Cognigate.getTierFromScore(800)).toBe(TrustTier.T5_TRUSTED);
76
+ expect(Cognigate.getTierFromScore(837)).toBe(TrustTier.T5_TRUSTED);
77
+ expect(Cognigate.getTierFromScore(875)).toBe(TrustTier.T5_TRUSTED);
78
+ });
79
+
80
+ it('returns T6_CERTIFIED for scores 876-949', () => {
81
+ expect(Cognigate.getTierFromScore(876)).toBe(TrustTier.T6_CERTIFIED);
82
+ expect(Cognigate.getTierFromScore(912)).toBe(TrustTier.T6_CERTIFIED);
83
+ expect(Cognigate.getTierFromScore(949)).toBe(TrustTier.T6_CERTIFIED);
84
+ });
85
+
86
+ it('returns T7_AUTONOMOUS for scores 950-1000', () => {
87
+ expect(Cognigate.getTierFromScore(950)).toBe(TrustTier.T7_AUTONOMOUS);
88
+ expect(Cognigate.getTierFromScore(975)).toBe(TrustTier.T7_AUTONOMOUS);
89
+ expect(Cognigate.getTierFromScore(1000)).toBe(TrustTier.T7_AUTONOMOUS);
90
+ });
91
+ });
92
+
93
+ describe('getTierName', () => {
94
+ it('returns correct tier names', () => {
95
+ expect(Cognigate.getTierName(TrustTier.T0_SANDBOX)).toBe('Sandbox');
96
+ expect(Cognigate.getTierName(TrustTier.T1_OBSERVED)).toBe('Observed');
97
+ expect(Cognigate.getTierName(TrustTier.T2_PROVISIONAL)).toBe('Provisional');
98
+ expect(Cognigate.getTierName(TrustTier.T3_VERIFIED)).toBe('Verified');
99
+ expect(Cognigate.getTierName(TrustTier.T4_OPERATIONAL)).toBe('Operational');
100
+ expect(Cognigate.getTierName(TrustTier.T5_TRUSTED)).toBe('Trusted');
101
+ expect(Cognigate.getTierName(TrustTier.T6_CERTIFIED)).toBe('Certified');
102
+ expect(Cognigate.getTierName(TrustTier.T7_AUTONOMOUS)).toBe('Autonomous');
103
+ });
104
+ });
105
+
106
+ describe('getTierThresholds', () => {
107
+ it('returns correct thresholds', () => {
108
+ const t4 = Cognigate.getTierThresholds(TrustTier.T4_OPERATIONAL);
109
+ expect(t4.min).toBe(650);
110
+ expect(t4.max).toBe(799);
111
+ expect(t4.name).toBe('Operational');
112
+ });
113
+ });
114
+ });
115
+
116
+ describe('TIER_THRESHOLDS', () => {
117
+ it('has all 8 tiers defined', () => {
118
+ expect(Object.keys(TIER_THRESHOLDS)).toHaveLength(8);
119
+ });
120
+
121
+ it('tiers are contiguous (no gaps)', () => {
122
+ const tiers = [
123
+ TrustTier.T0_SANDBOX,
124
+ TrustTier.T1_OBSERVED,
125
+ TrustTier.T2_PROVISIONAL,
126
+ TrustTier.T3_VERIFIED,
127
+ TrustTier.T4_OPERATIONAL,
128
+ TrustTier.T5_TRUSTED,
129
+ TrustTier.T6_CERTIFIED,
130
+ TrustTier.T7_AUTONOMOUS,
131
+ ];
132
+
133
+ for (let i = 0; i < tiers.length - 1; i++) {
134
+ const current = TIER_THRESHOLDS[tiers[i]];
135
+ const next = TIER_THRESHOLDS[tiers[i + 1]];
136
+ expect(current.max + 1).toBe(next.min);
137
+ }
138
+ });
139
+
140
+ it('covers full 0-1000 range', () => {
141
+ expect(TIER_THRESHOLDS[TrustTier.T0_SANDBOX].min).toBe(0);
142
+ expect(TIER_THRESHOLDS[TrustTier.T7_AUTONOMOUS].max).toBe(1000);
143
+ });
144
+ });
145
+
146
+ describe('CognigateError', () => {
147
+ it('creates error with all properties', () => {
148
+ const error = new CognigateError('Test error', 'TEST_CODE', 400, { foo: 'bar' });
149
+
150
+ expect(error.message).toBe('Test error');
151
+ expect(error.code).toBe('TEST_CODE');
152
+ expect(error.status).toBe(400);
153
+ expect(error.details).toEqual({ foo: 'bar' });
154
+ expect(error.name).toBe('CognigateError');
155
+ });
156
+
157
+ it('is instanceof Error', () => {
158
+ const error = new CognigateError('Test', 'CODE');
159
+ expect(error instanceof Error).toBe(true);
160
+ expect(error instanceof CognigateError).toBe(true);
161
+ });
162
+ });