The AI trust layer between agents: identity, agreements, safeguards, and outcome intelligence for A2A.

Viewing files at commit 8941e5beacddCommit detailsView latest

packages/protocol/src/index.ts 1362 lines · 46.9 KB · typescript
1
import { createHash, generateKeyPairSync, randomUUID, sign, verify } from 'node:crypto';
2
import { canonicalize } from 'json-canonicalize';
3
import { z } from 'zod';
4
5
export const PROTOCOL_VERSION = '0.1' as const;
6
export const DEFAULT_EXTENSION_URI = 'https://openclasp.vercel.app/extensions/trust/v0.1';
7
8
export const OPENCLASP_AUTH_SCOPES = [
9
  'mcp:access',
10
  'runtime:connect',
11
  'profile:read',
12
  'interaction:write',
13
  'feedback:write',
14
  'agent:manage',
15
  'network:contribute',
16
] as const;
17
export type OpenClaspAuthScope = (typeof OPENCLASP_AUTH_SCOPES)[number];
18
export const DEFAULT_AGENT_AUTH_SCOPES: OpenClaspAuthScope[] = [
19
  'mcp:access',
20
  'runtime:connect',
21
  'profile:read',
22
  'interaction:write',
23
  'feedback:write',
24
  'agent:manage',
25
];
26
export const DEFAULT_MCP_AUTH_SCOPES: OpenClaspAuthScope[] = [
27
  'mcp:access',
28
  'profile:read',
29
  'interaction:write',
30
  'feedback:write',
31
  'agent:manage',
32
];
33
34
export const ProvenanceSchema = z.enum([
35
  'self_declared',
36
  'operator_attested',
37
  'cryptographically_verified',
38
  'domain_verified',
39
  'third_party_verified',
40
  'observed',
41
  'disputed',
42
]);
43
export const VisibilitySchema = z.enum([
44
  'local_only',
45
  'private_requester',
46
  'private_responder',
47
  'shared_participants',
48
  'network_aggregate',
49
]);
50
export const DataSharingModeSchema = z.enum([
51
  'local_only',
52
  'structured_only',
53
  'permitted_evidence',
54
]);
55
export const SignatureSchema = z.object({
56
  algorithm: z.literal('Ed25519'),
57
  keyId: z.string().min(1),
58
  value: z.string().min(1),
59
});
60
61
export const RecordAttestationSchema = SignatureSchema.extend({
62
  digest: z.string().regex(/^[a-zA-Z0-9_-]{43}$/),
63
}).strict();
64
65
export const RetentionClassSchema = z.enum(['account', 'audit', 'operational', 'temporary']);
66
export const LearningScopeSchema = z.enum([
67
  'not_evaluated',
68
  'excluded',
69
  'local_only',
70
  'network_aggregate',
71
]);
72
73
export const SourceRecordEnvelopeSchema = z
74
  .object({
75
    eventId: z.string().uuid(),
76
    operatorId: z.string().min(1),
77
    kind: z.string().regex(/^[a-z][a-z0-9_]*$/),
78
    recordId: z.string().min(1),
79
    schemaName: z.string().min(1),
80
    schemaVersion: z.string().min(1),
81
    payload: z.json(),
82
    payloadDigest: z.string().regex(/^[a-zA-Z0-9_-]{43}$/),
83
    entityRefs: z.record(z.string(), z.string().min(1)).default({}),
84
    provenance: ProvenanceSchema,
85
    visibility: VisibilitySchema,
86
    retentionClass: RetentionClassSchema,
87
    learningScope: LearningScopeSchema,
88
    reportedAt: z.string().datetime(),
89
    ingestedAt: z.string().datetime(),
90
  })
91
  .strict();
92
93
export const ExpectationManifestSchema = z.object({
94
  requiredInputs: z.array(z.string()).default([]),
95
  supportedTaskCategories: z.array(z.string()).min(1),
96
  responseTimeMs: z.number().int().positive().optional(),
97
  dataRequirements: z.array(z.string()).default([]),
98
  prohibitedData: z.array(z.string()).default([]),
99
  humanApprovalThresholds: z.array(z.string()).default([]),
100
  delegationPolicy: z.string().default('explicit'),
101
  evidenceRequirements: z.array(z.string()).default([]),
102
  factCheckingPreference: z
103
    .enum(['none', 'important_claims', 'all_objective_claims'])
104
    .default('important_claims'),
105
  mediationPreference: z.enum(['never', 'mutual_consent']).default('mutual_consent'),
106
  retentionDays: z.number().int().nonnegative().default(30),
107
  communicationFormats: z.array(z.string()).default(['text/plain']),
108
  cancellationPolicy: z.string().default('either_party'),
109
  provenance: ProvenanceSchema,
110
});
111
112
export const AgentIdentitySchema = z.object({
113
  protocolVersion: z.literal(PROTOCOL_VERSION),
114
  agentId: z.string().min(1),
115
  publicKey: z.string().min(1),
116
  keyId: z.string().min(1),
117
  operatorRef: z.string().min(1),
118
  assurance: z.enum(['pseudonymous', 'domain_associated', 'organization_associated']),
119
  agentVersion: z.string().min(1),
120
  capabilities: z.array(z.string()),
121
  supportedProtocols: z.array(z.string()),
122
  parentAgentId: z.string().optional(),
123
  rootControllerId: z.string().min(1),
124
  revoked: z.boolean().default(false),
125
  provenance: ProvenanceSchema,
126
  createdAt: z.string().datetime(),
127
  signature: SignatureSchema.optional(),
128
});
129
130
export const DelegationCredentialSchema = z.object({
131
  protocolVersion: z.literal(PROTOCOL_VERSION),
132
  delegationId: z.string().uuid(),
133
  parentAgentId: z.string(),
134
  childAgentId: z.string(),
135
  rootControllerId: z.string(),
136
  capabilities: z.array(z.string()).min(1),
137
  issuedAt: z.string().datetime(),
138
  expiresAt: z.string().datetime(),
139
  revoked: z.boolean().default(false),
140
  signature: SignatureSchema.optional(),
141
});
142
143
export const InteractionContractSchema = z.object({
144
  protocolVersion: z.literal(PROTOCOL_VERSION),
145
  interactionId: z.string().uuid(),
146
  purpose: z.string(),
147
  parties: z.array(z.string()).min(1),
148
  taskCategory: z.string(),
149
  requestedOutcome: z.string(),
150
  successCriteria: z.array(z.string()),
151
  allowedActions: z.array(z.string()),
152
  prohibitedActions: z.array(z.string()),
153
  allowedData: z.array(z.string()),
154
  prohibitedData: z.array(z.string()),
155
  deadline: z.string().datetime().optional(),
156
  evidenceRequirements: z.array(z.string()),
157
  delegationRules: z.array(z.string()),
158
  humanApprovalRequirements: z.array(z.string()),
159
  factCheckingPolicy: z.string(),
160
  mediationPolicy: z.enum(['none', 'mutual_consent']),
161
  retentionDays: z.number().int().nonnegative(),
162
  completionConditions: z.array(z.string()),
163
  cancellationConditions: z.array(z.string()),
164
  signatures: z.record(z.string(), SignatureSchema).default({}),
165
});
166
167
export const AgentTransportSchema = z.object({
168
  protocol: z.literal('A2A/1.0'),
169
  protocolBinding: z.string().min(1).default('JSONRPC'),
170
  endpoint: z.string().url(),
171
  managedBy: z.literal('agent').default('agent'),
172
});
173
174
export const AgentModeSchema = z.literal('persistent_runtime');
175
176
export const AgentPresenceSchema = z.object({
177
  status: z.enum(['online', 'offline']),
178
  lastSeenAt: z.string().datetime().optional(),
179
  checkedAt: z.string().datetime(),
180
});
181
182
export const PublicAgentVerificationSchema = z.object({
183
  status: z.literal('verified'),
184
  method: z.literal('openclasp_oauth_account'),
185
  verifiedAt: z.string().datetime(),
186
  verificationKeyUrl: z.string().url().optional(),
187
});
188
189
export const PublicAgentCardSchema = z.object({
190
  protocolVersion: z.literal(PROTOCOL_VERSION),
191
  agentId: z.string().min(1),
192
  name: z.string().min(1),
193
  description: z.string(),
194
  framework: z.string().min(1),
195
  agentVersion: z.string().min(1),
196
  capabilities: z.array(z.string()),
197
  limitations: z.array(z.string()),
198
  assurance: z.enum(['oauth_authenticated', 'cryptographically_verified']),
199
  agentMode: AgentModeSchema.default('persistent_runtime'),
200
  transports: z.array(AgentTransportSchema),
201
  slug: z
202
    .string()
203
    .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
204
    .optional(),
205
  profileUrl: z.string().url().optional(),
206
  cardUrl: z.string().url(),
207
  a2aAgentCardUrl: z.string().url(),
208
  extensionUri: z.string().url(),
209
  presence: AgentPresenceSchema.optional(),
210
  verification: PublicAgentVerificationSchema.optional(),
211
  publishedAt: z.string().datetime(),
212
  updatedAt: z.string().datetime(),
213
  platformAttestation: RecordAttestationSchema.optional(),
214
});
215
216
export const AgentResolutionSchema = z.object({
217
  reference: z.string().min(1),
218
  matchedBy: z.enum(['agent_id', 'slug', 'profile_url', 'card_url', 'a2a_card_url']),
219
  verified: z.literal(true),
220
  card: PublicAgentCardSchema,
221
  resolvedAt: z.string().datetime(),
222
});
223
224
export const ContractAcceptanceSchema = z.object({
225
  agentId: z.string().min(1),
226
  method: z.enum(['oauth_installation', 'oauth_account', 'policy_auto_accept', 'ed25519']),
227
  termsHash: z.string().min(1),
228
  acceptedAt: z.string().datetime(),
229
  signature: SignatureSchema.optional(),
230
});
231
232
export const ContractRevisionSchema = z.object({
233
  revisionId: z.string().uuid(),
234
  interactionId: z.string().uuid(),
235
  revision: z.number().int().positive(),
236
  previousTermsHash: z.string().min(1).optional(),
237
  termsHash: z.string().min(1),
238
  contract: InteractionContractSchema,
239
  proposedByAgentId: z.string().min(1),
240
  status: z.enum(['proposed', 'accepted', 'rejected', 'superseded']),
241
  acceptances: z.record(z.string(), ContractAcceptanceSchema),
242
  createdAt: z.string().datetime(),
243
  updatedAt: z.string().datetime(),
244
  expiresAt: z.string().datetime().optional(),
245
  platformAttestation: RecordAttestationSchema.optional(),
246
});
247
248
export const FederatedInteractionStatusSchema = z.enum([
249
  'pending',
250
  'active',
251
  'rejected',
252
  'expired',
253
  'cancelled',
254
  'completed',
255
]);
256
257
export const FederatedInteractionSchema = z.object({
258
  protocolVersion: z.literal(PROTOCOL_VERSION),
259
  interactionId: z.string().uuid(),
260
  initiatorAgentId: z.string().min(1),
261
  responderAgentId: z.string().min(1),
262
  status: FederatedInteractionStatusSchema,
263
  contract: InteractionContractSchema,
264
  termsHash: z.string().min(1),
265
  acceptances: z.record(z.string(), ContractAcceptanceSchema),
266
  contractRevision: z.number().int().positive().default(1),
267
  contractRevisions: z.array(ContractRevisionSchema).default([]),
268
  initiatorTransport: AgentTransportSchema.optional(),
269
  responderTransport: AgentTransportSchema,
270
  createdAt: z.string().datetime(),
271
  updatedAt: z.string().datetime(),
272
  expiresAt: z.string().datetime(),
273
});
274
275
export const LiveSessionInsightSchema = z
276
  .object({
277
    code: z.string().min(1),
278
    severity: z.enum(['info', 'caution', 'high']),
279
    message: z.string().min(1),
280
    evidenceReferences: z.array(z.string()).default([]),
281
    requirementReferences: z.array(z.string()).default([]),
282
    confidence: z.number().min(0).max(1).optional(),
283
  })
284
  .strict();
285
286
export const RequirementAssessmentSchema = z
287
  .object({
288
    requirementId: z.string().min(1).max(128),
289
    requirement: z.string().min(1).max(1000),
290
    kind: z.enum([
291
      'capability',
292
      'limitation',
293
      'success_criterion',
294
      'deadline',
295
      'evidence',
296
      'scope',
297
      'data',
298
      'communication',
299
      'delegation',
300
    ]),
301
    status: z.enum(['match', 'partial', 'mismatch', 'unknown']),
302
    reason: z.string().min(1).max(1000),
303
    confidence: z.number().min(0).max(1),
304
    sources: z
305
      .array(
306
        z.enum(['contract', 'self_declared', 'eligible_history', 'evidence', 'version_change']),
307
      )
308
      .min(1),
309
    evidenceReferences: z.array(z.string().min(1).max(2048)).max(50).default([]),
310
  })
311
  .strict();
312
313
export const CounterpartyBriefSchema = z
314
  .object({
315
    briefId: z.string().uuid(),
316
    interactionId: z.string().uuid(),
317
    contractHash: z.string().min(1),
318
    recipientAgentId: z.string().min(1),
319
    subjectAgentId: z.string().min(1),
320
    taskCategory: z.string().min(1),
321
    decision: z.enum(['ALLOW', 'CHALLENGE', 'DENY']),
322
    requirements: z.array(RequirementAssessmentSchema).max(100),
323
    insights: z.array(LiveSessionInsightSchema).max(100),
324
    relevantSampleSize: z.number().int().nonnegative(),
325
    historyConfidence: z.number().min(0).max(1),
326
    subjectAgentVersion: z.string().min(1),
327
    recommendedContractChanges: z.array(z.string().min(1).max(1000)).max(50).default([]),
328
    generatedAt: z.string().datetime(),
329
    expiresAt: z.string().datetime(),
330
    signature: SignatureSchema.optional(),
331
  })
332
  .strict()
333
  .refine((brief) => brief.recipientAgentId !== brief.subjectAgentId, {
334
    message: 'A counterparty brief must describe another agent',
335
    path: ['subjectAgentId'],
336
  })
337
  .refine((brief) => Date.parse(brief.expiresAt) > Date.parse(brief.generatedAt), {
338
    message: 'Counterparty brief expiry must be after generation',
339
    path: ['expiresAt'],
340
  });
341
342
export const LiveSessionOfferSchema = z.object({
343
  type: z.literal('openclasp.session.offer'),
344
  version: z.literal('1'),
345
  offerId: z.string().uuid(),
346
  interactionId: z.string().uuid(),
347
  agentId: z.string().min(1),
348
  role: z.enum(['initiator', 'responder']),
349
  counterparty: z.object({
350
    agentId: z.string().min(1),
351
    name: z.string().min(1),
352
    agentVersion: z.string().min(1),
353
    capabilities: z.array(z.string()),
354
  }),
355
  contract: InteractionContractSchema,
356
  contractHash: z.string().min(1),
357
  privateInsights: z.array(LiveSessionInsightSchema).default([]),
358
  counterpartyBrief: CounterpartyBriefSchema.optional(),
359
  issuedAt: z.string().datetime(),
360
  expiresAt: z.string().datetime(),
361
});
362
363
export const LiveSessionAcceptanceSchema = z.object({
364
  type: z.literal('openclasp.session.accepted'),
365
  version: z.literal('1'),
366
  offerId: z.string().uuid(),
367
  interactionId: z.string().uuid(),
368
  agentId: z.string().min(1),
369
  sessionId: z.string().uuid(),
370
  a2aEndpoint: z.string().url(),
371
  expiresAt: z.string().datetime(),
372
});
373
374
export const LiveSessionActivationSchema = z.object({
375
  type: z.literal('openclasp.session.activation'),
376
  version: z.literal('1'),
377
  activationId: z.string().uuid(),
378
  interactionId: z.string().uuid(),
379
  agentId: z.string().min(1),
380
  sessionId: z.string().uuid(),
381
  role: z.enum(['initiator', 'responder']),
382
  peer: z.object({
383
    agentId: z.string().min(1),
384
    sessionId: z.string().uuid(),
385
    endpoint: z.string().url(),
386
    bearerToken: z.string().min(1),
387
    verificationKey: z.string().min(1),
388
  }),
389
  reporting: z.object({
390
    endpoint: z.string().url(),
391
    completionEndpoint: z.string().url().optional(),
392
    feedbackEndpoint: z.string().url().optional(),
393
    assuranceResponseEndpoint: z.string().url().optional(),
394
    bearerToken: z.string().min(1),
395
  }),
396
  privateInsights: z.array(LiveSessionInsightSchema).optional(),
397
  counterpartyBrief: CounterpartyBriefSchema.optional(),
398
  contractHash: z.string().min(1),
399
  activatedAt: z.string().datetime(),
400
  expiresAt: z.string().datetime(),
401
});
402
403
const SessionDetailKeySchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]{0,63}$/);
404
405
export const StructuredSessionDetailsSchema = z
406
  .object({
407
    labels: z.array(SessionDetailKeySchema).max(32).default([]),
408
    metrics: z.record(SessionDetailKeySchema, z.number().finite()).default({}),
409
    flags: z.record(SessionDetailKeySchema, z.boolean()).default({}),
410
  })
411
  .strict()
412
  .default({ labels: [], metrics: {}, flags: {} });
413
414
export const ProgressCheckpointSchema = z
415
  .object({
416
    state: z.enum(['active', 'blocked', 'ready_to_finalize', 'done', 'cancelled']),
417
    progress: z.number().min(0).max(1),
418
    criteriaMet: z.array(z.string().min(1).max(1000)).max(100).default([]),
419
    criteriaRemaining: z.array(z.string().min(1).max(1000)).max(100).default([]),
420
    blockerCodes: z.array(SessionDetailKeySchema).max(32).default([]),
421
    topicStatus: z.enum(['in_scope', 'drifting', 'changed']),
422
    expectedRemainingTurns: z.number().int().nonnegative().max(1000).optional(),
423
    needsHuman: z.boolean().default(false),
424
    confidence: z.number().min(0).max(1),
425
  })
426
  .strict();
427
428
export const AssuranceProbePhaseSchema = z.enum(['pre_task', 'post_task']);
429
export const AssuranceProbeResponseTypeSchema = z.enum(['boolean', 'enum', 'number', 'short_text']);
430
export const AssuranceRiskDimensionSchema = z.enum([
431
  'capability',
432
  'scope',
433
  'deadline',
434
  'tool_access',
435
  'data_access',
436
  'evidence',
437
  'dependency',
438
  'authority',
439
  'safety',
440
  'delivery',
441
]);
442
export const AssuranceSignalEffectSchema = z.enum([
443
  'increase_success',
444
  'reduce_success',
445
  'neutral',
446
]);
447
export const AssuranceExpectedSignalSchema = z
448
  .object({
449
    answer: z.string().trim().min(1).max(80),
450
    effect: AssuranceSignalEffectSchema,
451
    probabilityDelta: z.number().min(-0.5).max(0.5),
452
  })
453
  .strict();
454
455
export const AssuranceProbeQuestionSchema = z
456
  .object({
457
    probeId: z.string().uuid(),
458
    questionCode: z.string().regex(/^[a-z][a-z0-9_]{1,63}$/),
459
    prompt: z.string().trim().min(1).max(240),
460
    responseType: AssuranceProbeResponseTypeSchema,
461
    choices: z.array(z.string().trim().min(1).max(80)).min(2).max(6).optional(),
462
    evidenceRequested: z.boolean().default(false),
463
    required: z.boolean().default(true),
464
    questionFamily: AssuranceRiskDimensionSchema,
465
    riskHypothesis: z.string().trim().min(1).max(280),
466
    expectedSignals: z.array(AssuranceExpectedSignalSchema).min(1).max(6),
467
    expectedInformationGain: z.number().min(0).max(1),
468
    selectionReason: z.string().trim().min(1).max(280),
469
    recommendedSafeguardCodes: z
470
      .array(z.string().regex(/^[a-z][a-z0-9_]{1,63}$/))
471
      .max(5)
472
      .default([]),
473
  })
474
  .strict()
475
  .superRefine((question, context) => {
476
    if (question.responseType === 'enum' && !question.choices)
477
      context.addIssue({
478
        code: 'custom',
479
        path: ['choices'],
480
        message: 'Enum assurance probes require bounded choices',
481
      });
482
    if (question.responseType !== 'enum' && question.choices)
483
      context.addIssue({
484
        code: 'custom',
485
        path: ['choices'],
486
        message: 'Choices are only valid for enum assurance probes',
487
      });
488
  });
489
490
export const AssuranceProbePlanSchema = z
491
  .object({
492
    protocolVersion: z.literal(PROTOCOL_VERSION),
493
    planId: z.string().uuid(),
494
    interactionId: z.string().uuid(),
495
    contractHash: z.string().min(1),
496
    phase: AssuranceProbePhaseSchema,
497
    generatedForAgentId: z.string().min(1),
498
    targetAgentId: z.string().min(1),
499
    targetAgentVersion: z.string().min(1).max(200),
500
    round: z.number().int().min(1).max(3),
501
    assessmentId: z.string().uuid(),
502
    predictionBeforeId: z.string().uuid(),
503
    questions: z.array(AssuranceProbeQuestionSchema).length(1),
504
    generation: z
505
      .object({
506
        generationId: z.string().uuid(),
507
        mode: z.enum(['ai', 'fallback']),
508
        model: z.string().min(1),
509
        promptVersion: z.string().min(1),
510
      })
511
      .strict(),
512
    generatedAt: z.string().datetime(),
513
    expiresAt: z.string().datetime(),
514
  })
515
  .strict();
516
517
export const AssuranceRiskSchema = z
518
  .object({
519
    riskCode: z.string().regex(/^[a-z][a-z0-9_]{1,63}$/),
520
    dimension: AssuranceRiskDimensionSchema,
521
    title: z.string().trim().min(1).max(160),
522
    rationale: z.string().trim().min(1).max(500),
523
    likelihood: z.number().min(0).max(1),
524
    impact: z.number().min(0).max(1),
525
    confidence: z.number().min(0).max(1),
526
    evidenceReferences: z.array(z.string().trim().min(1).max(2048)).max(10).default([]),
527
  })
528
  .strict();
529
530
export const AssurancePredictionSnapshotSchema = z
531
  .object({
532
    protocolVersion: z.literal(PROTOCOL_VERSION),
533
    predictionId: z.string().uuid(),
534
    interactionId: z.string().uuid(),
535
    contractHash: z.string().min(1),
536
    targetAgentId: z.string().min(1),
537
    targetAgentVersion: z.string().min(1).max(200),
538
    taskCategory: z.string().trim().min(1).max(100),
539
    stage: z.enum(['baseline', 'after_probe', 'after_safeguard', 'final']),
540
    successProbability: z.number().min(0.05).max(0.95),
541
    confidence: z.number().min(0).max(1),
542
    basis: z.enum(['cold_start_hybrid', 'historical_hybrid', 'deterministic_fallback']),
543
    sampleSize: z.number().int().nonnegative(),
544
    topRiskCodes: z.array(z.string().regex(/^[a-z][a-z0-9_]{1,63}$/)).max(5),
545
    featureVersion: z.string().min(1).max(100),
546
    generationId: z.string().uuid().optional(),
547
    priorPredictionId: z.string().uuid().optional(),
548
    triggerResponseId: z.string().uuid().optional(),
549
    createdAt: z.string().datetime(),
550
  })
551
  .strict();
552
553
export const AssuranceSafeguardSchema = z
554
  .object({
555
    safeguardId: z.string().uuid(),
556
    assessmentId: z.string().uuid(),
557
    safeguardCode: z.string().regex(/^[a-z][a-z0-9_]{1,63}$/),
558
    interactionId: z.string().uuid(),
559
    contractHash: z.string().min(1),
560
    targetAgentId: z.string().min(1),
561
    targetAgentVersion: z.string().min(1).max(200),
562
    type: z.enum([
563
      'require_evidence',
564
      'narrow_scope',
565
      'extend_deadline',
566
      'grant_tool_access',
567
      'require_human_approval',
568
      'limit_delegation',
569
      'add_checkpoint',
570
      'choose_another_agent',
571
    ]),
572
    description: z.string().trim().min(1).max(500),
573
    rationale: z.string().trim().min(1).max(500),
574
    riskCodes: z
575
      .array(z.string().regex(/^[a-z][a-z0-9_]{1,63}$/))
576
      .min(1)
577
      .max(5),
578
    expectedImpact: z.number().min(0).max(0.5),
579
    status: z.enum(['recommended', 'accepted', 'rejected', 'modified']),
580
    decisionReason: z.string().trim().max(500).optional(),
581
    decidedAt: z.string().datetime().optional(),
582
    createdAt: z.string().datetime(),
583
  })
584
  .strict();
585
586
export const AssuranceDecisionSchema = z
587
  .object({
588
    protocolVersion: z.literal(PROTOCOL_VERSION),
589
    assessmentId: z.string().uuid(),
590
    interactionId: z.string().uuid(),
591
    contractHash: z.string().min(1),
592
    phase: AssuranceProbePhaseSchema,
593
    round: z.number().int().min(1).max(3),
594
    generatedForAgentId: z.string().min(1),
595
    targetAgentId: z.string().min(1),
596
    targetAgentVersion: z.string().min(1).max(200),
597
    prediction: AssurancePredictionSnapshotSchema,
598
    risks: z.array(AssuranceRiskSchema).max(5),
599
    candidateQuestions: z.array(AssuranceProbeQuestionSchema).max(5),
600
    selectedProbeId: z.string().uuid().optional(),
601
    safeguards: z.array(AssuranceSafeguardSchema).max(5),
602
    advisoryNotice: z.literal('experimental_estimate_not_a_guarantee'),
603
    generation: z
604
      .object({
605
        generationId: z.string().uuid(),
606
        mode: z.enum(['ai', 'fallback']),
607
        model: z.string().min(1),
608
        promptVersion: z.string().min(1),
609
      })
610
      .strict(),
611
    createdAt: z.string().datetime(),
612
  })
613
  .strict();
614
615
export const AssuranceEffectivenessEvaluationSchema = z
616
  .object({
617
    protocolVersion: z.literal(PROTOCOL_VERSION),
618
    evaluationId: z.string().uuid(),
619
    interactionId: z.string().uuid(),
620
    contractHash: z.string().min(1),
621
    targetAgentId: z.string().min(1),
622
    targetAgentVersion: z.string().min(1).max(200),
623
    taskCategory: z.string().trim().min(1).max(100),
624
    completionReportId: z.string().uuid(),
625
    outcomeValue: z.number().min(0).max(1),
626
    predictionScores: z
627
      .array(
628
        z
629
          .object({
630
            predictionId: z.string().uuid(),
631
            stage: AssurancePredictionSnapshotSchema.shape.stage,
632
            probability: z.number().min(0.05).max(0.95),
633
            brierScore: z.number().min(0).max(1),
634
          })
635
          .strict(),
636
      )
637
      .max(20),
638
    questionScores: z
639
      .array(
640
        z
641
          .object({
642
            probeId: z.string().uuid(),
643
            questionCode: z.string().min(1),
644
            questionFamily: AssuranceRiskDimensionSchema,
645
            answered: z.boolean(),
646
            exposedMaterialRisk: z.boolean(),
647
            predictionDelta: z.number().min(-0.9).max(0.9),
648
          })
649
          .strict(),
650
      )
651
      .max(6),
652
    safeguardScores: z
653
      .array(
654
        z
655
          .object({
656
            safeguardId: z.string().uuid(),
657
            type: AssuranceSafeguardSchema.shape.type,
658
            status: AssuranceSafeguardSchema.shape.status,
659
            outcomeAssociation: z.enum(['positive', 'negative', 'unclear']),
660
            causalClaim: z.literal(false),
661
          })
662
          .strict(),
663
      )
664
      .max(10),
665
    evaluatedAt: z.string().datetime(),
666
  })
667
  .strict();
668
669
const AssuranceProbeAnswerBaseSchema = z.object({
670
  probeId: z.string().uuid(),
671
  questionCode: z.string().regex(/^[a-z][a-z0-9_]{1,63}$/),
672
  confidence: z.number().min(0).max(1),
673
  evidenceReferences: z.array(z.string().trim().min(1).max(2048)).max(5).default([]),
674
  limitations: z.array(z.string().trim().min(1).max(240)).max(3).default([]),
675
});
676
677
export const AssuranceProbeAnswerSchema = z.discriminatedUnion('responseType', [
678
  AssuranceProbeAnswerBaseSchema.extend({
679
    responseType: z.literal('boolean'),
680
    answer: z.boolean(),
681
  }).strict(),
682
  AssuranceProbeAnswerBaseSchema.extend({
683
    responseType: z.literal('enum'),
684
    answer: z.string().trim().min(1).max(80),
685
  }).strict(),
686
  AssuranceProbeAnswerBaseSchema.extend({
687
    responseType: z.literal('number'),
688
    answer: z.number().finite(),
689
  }).strict(),
690
  AssuranceProbeAnswerBaseSchema.extend({
691
    responseType: z.literal('short_text'),
692
    answer: z.string().trim().min(1).max(280),
693
  }).strict(),
694
]);
695
696
export const AssuranceProbeResponseSchema = z
697
  .object({
698
    protocolVersion: z.literal(PROTOCOL_VERSION),
699
    responseId: z.string().uuid(),
700
    planId: z.string().uuid(),
701
    interactionId: z.string().uuid(),
702
    contractHash: z.string().min(1),
703
    phase: AssuranceProbePhaseSchema,
704
    agentId: z.string().min(1),
705
    agentVersion: z.string().min(1).max(200),
706
    answers: z.array(AssuranceProbeAnswerSchema).length(1),
707
    respondedAt: z.string().datetime(),
708
  })
709
  .strict();
710
711
export const AssuranceClaimComparisonSchema = z
712
  .object({
713
    questionCode: z.string().regex(/^[a-z][a-z0-9_]{1,63}$/),
714
    preTaskClaim: z.union([z.boolean(), z.number(), z.string().max(280)]),
715
    observedOutcome: z.string().trim().min(1).max(500),
716
    status: z.enum(['aligned', 'partially_aligned', 'contradicted', 'unverifiable']),
717
    evidenceReferences: z.array(z.string().trim().min(1).max(2048)).max(10).default([]),
718
  })
719
  .strict();
720
721
export const AssuranceClaimOutcomeComparisonSchema = z
722
  .object({
723
    protocolVersion: z.literal(PROTOCOL_VERSION),
724
    comparisonId: z.string().uuid(),
725
    interactionId: z.string().uuid(),
726
    contractHash: z.string().min(1),
727
    targetAgentId: z.string().min(1),
728
    preTaskResponseId: z.string().uuid(),
729
    postTaskResponseId: z.string().uuid().optional(),
730
    completionReportIds: z.array(z.string().uuid()).max(2).default([]),
731
    comparisons: z.array(AssuranceClaimComparisonSchema).max(3),
732
    calculatedAt: z.string().datetime(),
733
  })
734
  .strict();
735
736
export const AssuranceProbeA2APayloadSchema = z
737
  .object({
738
    kind: z.literal('openclasp.assurance.probe'),
739
    plan: AssuranceProbePlanSchema,
740
  })
741
  .strict();
742
743
export const AssuranceResponseA2APayloadSchema = z
744
  .object({
745
    kind: z.literal('openclasp.assurance.response'),
746
    response: AssuranceProbeResponseSchema,
747
  })
748
  .strict();
749
750
export const LiveSessionEventSchema = z
751
  .object({
752
    eventId: z.string().uuid(),
753
    interactionId: z.string().uuid(),
754
    agentId: z.string().min(1),
755
    sequence: z.number().int().nonnegative(),
756
    type: z.enum([
757
      'session_started',
758
      'message_sent',
759
      'progress_checkpoint',
760
      'claim',
761
      'evidence',
762
      'correction',
763
      'constraint',
764
      'task_result',
765
      'session_completed',
766
      'session_failed',
767
    ]),
768
    occurredAt: z.string().datetime(),
769
    messageHash: z
770
      .string()
771
      .regex(/^[a-zA-Z0-9_-]{43}$/)
772
      .optional(),
773
    evidenceReferences: z.array(z.string()).default([]),
774
    outcome: z.enum(['success', 'failure', 'partial']).optional(),
775
    checkpoint: ProgressCheckpointSchema.optional(),
776
    details: StructuredSessionDetailsSchema,
777
  })
778
  .superRefine((event, context) => {
779
    if (event.type === 'progress_checkpoint' && !event.checkpoint)
780
      context.addIssue({
781
        code: 'custom',
782
        path: ['checkpoint'],
783
        message: 'Progress checkpoint events require structured checkpoint data',
784
      });
785
    if (event.type !== 'progress_checkpoint' && event.checkpoint)
786
      context.addIssue({
787
        code: 'custom',
788
        path: ['checkpoint'],
789
        message: 'Checkpoint data is only valid on progress checkpoint events',
790
      });
791
  });
792
793
export const LiveSessionStateRecordSchema = z
794
  .object({
795
    interactionId: z.string().uuid(),
796
    initiatorAgentId: z.string().min(1),
797
    responderAgentId: z.string().min(1),
798
    status: z.enum(['preparing', 'active', 'completed', 'failed']),
799
    expiresAt: z.string().datetime(),
800
    createdAt: z.string().datetime(),
801
    activatedAt: z.string().datetime().optional(),
802
    completedAt: z.string().datetime().optional(),
803
    failureCode: z.literal('session_failed').optional(),
804
  })
805
  .strict();
806
807
export const CompletionOutcomeSchema = z.enum(['success', 'partial', 'failure', 'cancelled']);
808
809
export const SuccessCriterionAssessmentSchema = z
810
  .object({
811
    criterion: z.string().min(1).max(1000),
812
    status: z.enum(['met', 'partially_met', 'missed', 'unknown']),
813
    explanation: z.string().max(1000).optional(),
814
    evidenceReferences: z.array(z.string().min(1).max(2048)).max(50).default([]),
815
  })
816
  .strict();
817
818
export const InteractionCompletionReportSchema = z
819
  .object({
820
    reportId: z.string().uuid(),
821
    interactionId: z.string().uuid(),
822
    contractHash: z.string().min(1),
823
    reportingAgentId: z.string().min(1),
824
    counterpartyAgentId: z.string().min(1),
825
    agentVersion: z.string().min(1),
826
    outcome: CompletionOutcomeSchema,
827
    summary: z.string().min(1).max(2000),
828
    requestedOutcome: z.string().min(1).max(1000),
829
    criteria: z.array(SuccessCriterionAssessmentSchema).max(100),
830
    deliverables: z.array(z.string().min(1).max(1000)).max(100).default([]),
831
    actionsTaken: z.array(z.string().min(1).max(1000)).max(100).default([]),
832
    blockers: z.array(z.string().min(1).max(1000)).max(100).default([]),
833
    scopeChanges: z.array(z.string().min(1).max(1000)).max(100).default([]),
834
    corrections: z.array(z.string().min(1).max(1000)).max(100).default([]),
835
    evidenceReferences: z.array(z.string().min(1).max(2048)).max(100).default([]),
836
    startedAt: z.string().datetime().optional(),
837
    completedAt: z.string().datetime(),
838
    confidence: z.number().min(0).max(1),
839
    dataSharingMode: DataSharingModeSchema.default('structured_only'),
840
    signature: SignatureSchema.optional(),
841
    submissionMethod: z
842
      .enum([
843
        'agent_signature',
844
        'oauth_account',
845
        'oauth_installation',
846
        'agent_access_token',
847
        'runtime_session',
848
      ])
849
      .optional(),
850
    platformAttestation: RecordAttestationSchema.optional(),
851
  })
852
  .strict()
853
  .refine((report) => report.reportingAgentId !== report.counterpartyAgentId, {
854
    message: 'A completion report must describe an interaction with another agent',
855
    path: ['counterpartyAgentId'],
856
  })
857
  .refine(
858
    (report) => !report.startedAt || Date.parse(report.completedAt) >= Date.parse(report.startedAt),
859
    { message: 'Completion cannot precede the start time', path: ['completedAt'] },
860
  );
861
862
export const FeedbackDimensionSchema = z.enum([
863
  'overall_satisfaction',
864
  'outcome_satisfaction',
865
  'communication',
866
  'timeliness',
867
  'scope_adherence',
868
  'evidence_quality',
869
  'correction_handling',
870
  'limitation_disclosure',
871
  'reliability',
872
]);
873
874
export const FeedbackRequestSchema = z
875
  .object({
876
    requestId: z.string().uuid(),
877
    interactionId: z.string().uuid(),
878
    reviewerAgentId: z.string().min(1),
879
    subjectAgentId: z.string().min(1),
880
    status: z.enum(['pending', 'submitted', 'expired', 'waived']),
881
    requestedDimensions: z.array(FeedbackDimensionSchema).min(1),
882
    requestedAt: z.string().datetime(),
883
    dueAt: z.string().datetime(),
884
    platformAttestation: RecordAttestationSchema.optional(),
885
  })
886
  .strict()
887
  .refine((request) => request.reviewerAgentId !== request.subjectAgentId, {
888
    message: 'Feedback must concern another agent',
889
    path: ['subjectAgentId'],
890
  })
891
  .refine((request) => Date.parse(request.dueAt) > Date.parse(request.requestedAt), {
892
    message: 'Feedback due date must follow its request date',
893
    path: ['dueAt'],
894
  });
895
896
export const InteractionFeedbackSchema = z
897
  .object({
898
    feedbackId: z.string().uuid(),
899
    requestId: z.string().uuid(),
900
    interactionId: z.string().uuid(),
901
    reviewerAgentId: z.string().min(1),
902
    subjectAgentId: z.string().min(1),
903
    reviewerAgentVersion: z.string().min(1),
904
    ratings: z.partialRecord(FeedbackDimensionSchema, z.number().min(0).max(1)),
905
    wouldWorkAgain: z.enum(['yes', 'no', 'unsure']),
906
    reasonCodes: z.array(z.string().min(1).max(128)).max(32).default([]),
907
    privateComment: z.string().max(1000).optional(),
908
    evidenceReferences: z.array(z.string().min(1).max(2048)).max(50).default([]),
909
    confidence: z.number().min(0).max(1),
910
    submittedAt: z.string().datetime(),
911
    signature: SignatureSchema.optional(),
912
    submissionMethod: z
913
      .enum([
914
        'agent_signature',
915
        'oauth_account',
916
        'oauth_installation',
917
        'agent_access_token',
918
        'runtime_session',
919
      ])
920
      .optional(),
921
    platformAttestation: RecordAttestationSchema.optional(),
922
  })
923
  .strict()
924
  .refine((feedback) => feedback.reviewerAgentId !== feedback.subjectAgentId, {
925
    message: 'Feedback must concern another agent',
926
    path: ['subjectAgentId'],
927
  })
928
  .refine((feedback) => Object.keys(feedback.ratings).length > 0, {
929
    message: 'At least one feedback rating is required',
930
    path: ['ratings'],
931
  });
932
933
export const InteractionConclusionSchema = z
934
  .object({
935
    conclusionId: z.string().uuid(),
936
    interactionId: z.string().uuid(),
937
    contractHash: z.string().min(1),
938
    outcome: CompletionOutcomeSchema,
939
    consensus: z.enum([
940
      'bilateral_agreement',
941
      'bilateral_partial_agreement',
942
      'conflicting',
943
      'unilateral',
944
      'insufficient',
945
    ]),
946
    lifecycle: z.enum(['provisional', 'final']).optional(),
947
    confidence: z.number().min(0).max(1).optional(),
948
    missingReportAgentIds: z.array(z.string().min(1)).max(2).optional(),
949
    pendingFeedbackAgentIds: z.array(z.string().min(1)).max(2).optional(),
950
    peerReportStatus: z.enum(['awaiting', 'unreachable', 'received', 'timed_out']).optional(),
951
    summary: z.string().min(1).max(2000),
952
    criteria: z.array(SuccessCriterionAssessmentSchema).max(100),
953
    reportIds: z.array(z.string().uuid()).max(2),
954
    feedbackIds: z.array(z.string().uuid()).max(2),
955
    averageRatings: z.partialRecord(FeedbackDimensionSchema, z.number().min(0).max(1)).default({}),
956
    evidenceReferences: z.array(z.string().min(1).max(2048)).max(100).default([]),
957
    generatedAt: z.string().datetime(),
958
    platformAttestation: RecordAttestationSchema.optional(),
959
  })
960
  .strict();
961
962
export const LearningEligibilityDecisionSchema = z
963
  .object({
964
    decisionId: z.string().uuid(),
965
    interactionId: z.string().uuid(),
966
    eligible: z.boolean(),
967
    reasons: z.array(z.string().min(1).max(500)).min(1).max(50),
968
    sampleWeight: z.number().min(0).max(1),
969
    reportIds: z.array(z.string().uuid()).max(2),
970
    feedbackIds: z.array(z.string().uuid()).max(2),
971
    evidenceReferences: z.array(z.string().min(1).max(2048)).max(100).default([]),
972
    manipulationSignals: z.array(z.string().min(1).max(128)).max(20).default([]),
973
    contributionMode: z.enum(['local_only', 'network_aggregate']),
974
    structuredDataOnly: z.literal(true),
975
    decidedAt: z.string().datetime(),
976
    platformAttestation: RecordAttestationSchema.optional(),
977
  })
978
  .strict();
979
980
export const BehaviouralProfileDeltaSchema = z
981
  .object({
982
    deltaId: z.string().uuid(),
983
    interactionId: z.string().uuid(),
984
    agentId: z.string().min(1),
985
    agentVersion: z.string().min(1),
986
    taskCategory: z.string().min(1),
987
    sampleWeight: z.number().min(0).max(1),
988
    dimensionDeltas: z.record(z.string().min(1).max(128), z.number().min(-1).max(1)),
989
    explanation: z.string().min(1).max(2000),
990
    appliedAt: z.string().datetime(),
991
    platformAttestation: RecordAttestationSchema.optional(),
992
  })
993
  .strict();
994
995
export const BehaviouralDimensionNameSchema = z.enum([
996
  'completion',
997
  'acceptance',
998
  'specification',
999
  'deadline',
1000
  'communication',
1001
  'evidence',
1002
  'scope',
1003
  'correction',
1004
  'limitations',
1005
  'disputes',
1006
]);
1007
1008
export const ContextualReliabilitySummarySchema = z
1009
  .object({
1010
    agentId: z.string().min(1),
1011
    agentVersion: z.string().min(1),
1012
    taskCategory: z.string().min(1),
1013
    score: z.number().min(0).max(1),
1014
    confidence: z.object({
1015
      level: z.enum(['low', 'medium', 'high']),
1016
      value: z.number().min(0).max(1),
1017
      evidenceCount: z.number().int().nonnegative(),
1018
      effectiveSampleSize: z.number().nonnegative(),
1019
    }),
1020
    trend: z.object({
1021
      direction: z.enum(['improving', 'stable', 'declining']),
1022
      delta: z.number().min(-1).max(1),
1023
    }),
1024
    strengths: z
1025
      .array(
1026
        z.object({
1027
          dimension: BehaviouralDimensionNameSchema,
1028
          score: z.number().min(0).max(1),
1029
        }),
1030
      )
1031
      .max(3),
1032
    risks: z
1033
      .array(
1034
        z.object({
1035
          dimension: BehaviouralDimensionNameSchema,
1036
          score: z.number().min(0).max(1),
1037
          reason: z.string().min(1).max(300),
1038
        }),
1039
      )
1040
      .max(3),
1041
    versionStatus: z.object({
1042
      currentVersion: z.string().min(1),
1043
      evidenceVersion: z.string().min(1),
1044
      status: z.enum(['current', 'reduced_confidence']),
1045
    }),
1046
    source: z.literal('private_verified_history'),
1047
    updatedAt: z.string().datetime(),
1048
  })
1049
  .strict();
1050
1051
export const TrustEnvelopeSchema = z.object({
1052
  protocolVersion: z.literal(PROTOCOL_VERSION),
1053
  interactionId: z.string().uuid(),
1054
  requestingAgentId: z.string(),
1055
  respondingAgentId: z.string(),
1056
  rootControllerId: z.string(),
1057
  parentAgentId: z.string().optional(),
1058
  agentVersion: z.string(),
1059
  delegationId: z.string().uuid().optional(),
1060
  requestedCapability: z.string(),
1061
  taskCategory: z.string(),
1062
  contractHash: z.string(),
1063
  dataSharingMode: DataSharingModeSchema,
1064
  evidenceRequirements: z.array(z.string()),
1065
  timestamp: z.string().datetime(),
1066
  expiresAt: z.string().datetime(),
1067
  nonce: z.string().min(12),
1068
  signature: SignatureSchema.optional(),
1069
});
1070
1071
export const EventTypeSchema = z.enum([
1072
  'claim',
1073
  'evidence',
1074
  'constraint',
1075
  'commitment',
1076
  'proposal',
1077
  'objection',
1078
  'policy_warning',
1079
  'policy_violation',
1080
  'private_suggestion',
1081
  'shared_intervention',
1082
  'delegation',
1083
  'task_result',
1084
  'resolution',
1085
  'receipt',
1086
  'feedback',
1087
  'dispute',
1088
]);
1089
export const InteractionEventSchema = z.object({
1090
  protocolVersion: z.literal(PROTOCOL_VERSION),
1091
  eventId: z.string().uuid(),
1092
  interactionId: z.string().uuid(),
1093
  eventType: EventTypeSchema,
1094
  agentId: z.string(),
1095
  agentVersion: z.string(),
1096
  timestamp: z.string().datetime(),
1097
  visibility: VisibilitySchema,
1098
  provenance: ProvenanceSchema,
1099
  payloadHash: z.string(),
1100
  payload: z.record(z.string(), z.unknown()),
1101
  evidenceRefs: z.array(z.string()).optional(),
1102
  signature: SignatureSchema.optional(),
1103
});
1104
1105
export const FeedbackSchema = z.object({
1106
  feedbackId: z.string().uuid(),
1107
  interactionId: z.string().uuid(),
1108
  receiptId: z.string().uuid(),
1109
  reviewerAgentId: z.string(),
1110
  subjectAgentId: z.string(),
1111
  taskCompleted: z.boolean(),
1112
  outputAccepted: z.boolean(),
1113
  specificationMatched: z.boolean(),
1114
  deadlineMet: z.boolean(),
1115
  communicationQuality: z.number().min(0).max(1),
1116
  evidenceProvided: z.boolean(),
1117
  scopeRespected: z.boolean(),
1118
  disputeRaised: z.boolean(),
1119
  comment: z.string().max(1000).optional(),
1120
  submittedAt: z.string().datetime(),
1121
  signature: SignatureSchema.optional(),
1122
});
1123
1124
export const ReceiptSchema = z.object({
1125
  receiptId: z.string().uuid(),
1126
  interactionId: z.string().uuid(),
1127
  participants: z.array(z.string()),
1128
  agentVersions: z.record(z.string(), z.string()),
1129
  contractHash: z.string(),
1130
  startedAt: z.string().datetime(),
1131
  completedAt: z.string().datetime(),
1132
  outcome: z.enum(['success', 'partial', 'failure', 'cancelled']),
1133
  commitmentsFulfilled: z.array(z.string()),
1134
  commitmentsMissed: z.array(z.string()),
1135
  evidenceHashes: z.array(z.string()),
1136
  policyWarnings: z.array(z.string()),
1137
  policyViolations: z.array(z.string()),
1138
  disputeStatus: z.enum(['none', 'open', 'resolved']),
1139
  delegationChainHash: z.string(),
1140
  unilateral: z.boolean(),
1141
  provisional: z.boolean().optional(),
1142
  confidence: z.number().min(0).max(1).optional(),
1143
  signatures: z.record(z.string(), SignatureSchema).default({}),
1144
  completionReportIds: z.array(z.string().uuid()).max(2).optional(),
1145
  conclusionId: z.string().uuid().optional(),
1146
  platformAttestation: RecordAttestationSchema.optional(),
1147
});
1148
1149
export const RiskDecisionSchema = z.object({
1150
  decision: z.enum(['ALLOW', 'CHALLENGE', 'DENY']),
1151
  confidence: z.number().min(0).max(1),
1152
  taskCategory: z.string(),
1153
  sampleSize: z.number().int().nonnegative(),
1154
  dimensions: z.record(z.string(), z.number()),
1155
  reasons: z.array(z.string()),
1156
  warnings: z.array(z.string()),
1157
  dataFreshness: z.record(z.string(), z.string()),
1158
  requiredChallenges: z.array(z.string()),
1159
});
1160
1161
export const FactCheckResultSchema = z.object({
1162
  claim: z.string(),
1163
  claimType: z.enum(['objective', 'subjective', 'prediction']),
1164
  status: z.enum([
1165
    'verified',
1166
    'supported',
1167
    'contradicted',
1168
    'unverified',
1169
    'not_fact_checkable',
1170
    'insufficient_permission',
1171
  ]),
1172
  confidence: z.number().min(0).max(1),
1173
  evidenceReferences: z.array(z.string()),
1174
  sourceAuthority: z.string(),
1175
  sourceFreshness: z.string(),
1176
  contradictingEvidence: z.array(z.string()),
1177
  suggestedNextAction: z.string(),
1178
});
1179
1180
export type AgentIdentity = z.infer<typeof AgentIdentitySchema>;
1181
export type DelegationCredential = z.infer<typeof DelegationCredentialSchema>;
1182
export type InteractionContract = z.infer<typeof InteractionContractSchema>;
1183
export type TrustEnvelope = z.infer<typeof TrustEnvelopeSchema>;
1184
export type InteractionEvent = z.infer<typeof InteractionEventSchema>;
1185
export type Feedback = z.infer<typeof FeedbackSchema>;
1186
export type Receipt = z.infer<typeof ReceiptSchema>;
1187
export type RiskDecision = z.infer<typeof RiskDecisionSchema>;
1188
export type FactCheckResult = z.infer<typeof FactCheckResultSchema>;
1189
export type ExpectationManifest = z.infer<typeof ExpectationManifestSchema>;
1190
export type AgentTransport = z.infer<typeof AgentTransportSchema>;
1191
export type AgentMode = z.infer<typeof AgentModeSchema>;
1192
export type AgentPresence = z.infer<typeof AgentPresenceSchema>;
1193
export type PublicAgentVerification = z.infer<typeof PublicAgentVerificationSchema>;
1194
export type PublicAgentCard = z.infer<typeof PublicAgentCardSchema>;
1195
export type AgentResolution = z.infer<typeof AgentResolutionSchema>;
1196
export type ContractAcceptance = z.infer<typeof ContractAcceptanceSchema>;
1197
export type ContractRevision = z.infer<typeof ContractRevisionSchema>;
1198
export type FederatedInteraction = z.infer<typeof FederatedInteractionSchema>;
1199
export type LiveSessionInsight = z.infer<typeof LiveSessionInsightSchema>;
1200
export type LiveSessionOffer = z.infer<typeof LiveSessionOfferSchema>;
1201
export type LiveSessionAcceptance = z.infer<typeof LiveSessionAcceptanceSchema>;
1202
export type LiveSessionActivation = z.infer<typeof LiveSessionActivationSchema>;
1203
export type LiveSessionEvent = z.infer<typeof LiveSessionEventSchema>;
1204
export type LiveSessionStateRecord = z.infer<typeof LiveSessionStateRecordSchema>;
1205
export type AssuranceProbePhase = z.infer<typeof AssuranceProbePhaseSchema>;
1206
export type AssuranceProbeQuestion = z.infer<typeof AssuranceProbeQuestionSchema>;
1207
export type AssuranceProbePlan = z.infer<typeof AssuranceProbePlanSchema>;
1208
export type AssuranceProbeAnswer = z.infer<typeof AssuranceProbeAnswerSchema>;
1209
export type AssuranceProbeResponse = z.infer<typeof AssuranceProbeResponseSchema>;
1210
export type AssuranceClaimOutcomeComparison = z.infer<typeof AssuranceClaimOutcomeComparisonSchema>;
1211
export type AssuranceRiskDimension = z.infer<typeof AssuranceRiskDimensionSchema>;
1212
export type AssurancePredictionSnapshot = z.infer<typeof AssurancePredictionSnapshotSchema>;
1213
export type AssuranceRisk = z.infer<typeof AssuranceRiskSchema>;
1214
export type AssuranceSafeguard = z.infer<typeof AssuranceSafeguardSchema>;
1215
export type AssuranceDecision = z.infer<typeof AssuranceDecisionSchema>;
1216
export type AssuranceEffectivenessEvaluation = z.infer<
1217
  typeof AssuranceEffectivenessEvaluationSchema
1218
>;
1219
export type RequirementAssessment = z.infer<typeof RequirementAssessmentSchema>;
1220
export type CounterpartyBrief = z.infer<typeof CounterpartyBriefSchema>;
1221
export type CompletionOutcome = z.infer<typeof CompletionOutcomeSchema>;
1222
export type SuccessCriterionAssessment = z.infer<typeof SuccessCriterionAssessmentSchema>;
1223
export type InteractionCompletionReport = z.infer<typeof InteractionCompletionReportSchema>;
1224
export type FeedbackDimension = z.infer<typeof FeedbackDimensionSchema>;
1225
export type FeedbackRequest = z.infer<typeof FeedbackRequestSchema>;
1226
export type InteractionFeedback = z.infer<typeof InteractionFeedbackSchema>;
1227
export type InteractionConclusion = z.infer<typeof InteractionConclusionSchema>;
1228
export type LearningEligibilityDecision = z.infer<typeof LearningEligibilityDecisionSchema>;
1229
export type BehaviouralProfileDelta = z.infer<typeof BehaviouralProfileDeltaSchema>;
1230
export type BehaviouralDimensionName = z.infer<typeof BehaviouralDimensionNameSchema>;
1231
export type ContextualReliabilitySummary = z.infer<typeof ContextualReliabilitySummarySchema>;
1232
export type RecordAttestation = z.infer<typeof RecordAttestationSchema>;
1233
export type SourceRecordEnvelope = z.infer<typeof SourceRecordEnvelopeSchema>;
1234
export type RetentionClass = z.infer<typeof RetentionClassSchema>;
1235
export type LearningScope = z.infer<typeof LearningScopeSchema>;
1236
1237
export interface KeyPair {
1238
  keyId: string;
1239
  publicKey: string;
1240
  privateKey: string;
1241
}
1242
1243
export function createKeyPair(keyId: string = randomUUID()): KeyPair {
1244
  const pair = generateKeyPairSync('ed25519');
1245
  return {
1246
    keyId,
1247
    publicKey: pair.publicKey.export({ type: 'spki', format: 'der' }).toString('base64url'),
1248
    privateKey: pair.privateKey.export({ type: 'pkcs8', format: 'der' }).toString('base64url'),
1249
  };
1250
}
1251
1252
export function canonicalHash(value: unknown): string {
1253
  return createHash('sha256').update(canonicalize(value)).digest('base64url');
1254
}
1255
1256
export function verifyRecordAttestation(
1257
  value: Record<string, unknown>,
1258
  publicKey: string,
1259
): boolean {
1260
  const attestation = RecordAttestationSchema.safeParse(value.platformAttestation);
1261
  if (!attestation.success) return false;
1262
  const unsignedValue = structuredClone(value);
1263
  delete unsignedValue.platformAttestation;
1264
  const digest = canonicalHash(unsignedValue);
1265
  if (digest !== attestation.data.digest) return false;
1266
  return verify(
1267
    null,
1268
    Buffer.from(digest),
1269
    {
1270
      key: Buffer.from(publicKey, 'base64url'),
1271
      type: 'spki',
1272
      format: 'der',
1273
    },
1274
    Buffer.from(attestation.data.value, 'base64url'),
1275
  );
1276
}
1277
1278
function unsigned(value: Record<string, unknown>): Record<string, unknown> {
1279
  const copy = structuredClone(value);
1280
  delete copy.signature;
1281
  delete copy.signatures;
1282
  return copy;
1283
}
1284
1285
export function signObject<T extends Record<string, unknown>>(
1286
  value: T,
1287
  key: KeyPair,
1288
): T & { signature: z.infer<typeof SignatureSchema> } {
1289
  const payload = Buffer.from(canonicalize(unsigned(value)));
1290
  const privateKey = {
1291
    key: Buffer.from(key.privateKey, 'base64url'),
1292
    type: 'pkcs8' as const,
1293
    format: 'der' as const,
1294
  };
1295
  return {
1296
    ...value,
1297
    signature: {
1298
      algorithm: 'Ed25519',
1299
      keyId: key.keyId,
1300
      value: sign(null, payload, privateKey).toString('base64url'),
1301
    },
1302
  };
1303
}
1304
1305
export function verifyObject(value: Record<string, unknown>, publicKey: string): boolean {
1306
  const parsed = SignatureSchema.safeParse(value.signature);
1307
  if (!parsed.success) return false;
1308
  const key = {
1309
    key: Buffer.from(publicKey, 'base64url'),
1310
    type: 'spki' as const,
1311
    format: 'der' as const,
1312
  };
1313
  return verify(
1314
    null,
1315
    Buffer.from(canonicalize(unsigned(value))),
1316
    key,
1317
    Buffer.from(parsed.data.value, 'base64url'),
1318
  );
1319
}
1320
1321
export function signNamed<T extends Record<string, unknown>>(
1322
  value: T,
1323
  signerId: string,
1324
  key: KeyPair,
1325
): T & { signatures: Record<string, z.infer<typeof SignatureSchema>> } {
1326
  const payload = Buffer.from(canonicalize(unsigned(value)));
1327
  const privateKey = {
1328
    key: Buffer.from(key.privateKey, 'base64url'),
1329
    type: 'pkcs8' as const,
1330
    format: 'der' as const,
1331
  };
1332
  const signature = {
1333
    algorithm: 'Ed25519' as const,
1334
    keyId: key.keyId,
1335
    value: sign(null, payload, privateKey).toString('base64url'),
1336
  };
1337
  return {
1338
    ...value,
1339
    signatures: { ...((value.signatures as object) ?? {}), [signerId]: signature },
1340
  };
1341
}
1342
1343
export function verifyNamed(
1344
  value: Record<string, unknown>,
1345
  signerId: string,
1346
  publicKey: string,
1347
): boolean {
1348
  const signatures = value.signatures as Record<string, unknown> | undefined;
1349
  const parsed = SignatureSchema.safeParse(signatures?.[signerId]);
1350
  if (!parsed.success) return false;
1351
  const key = {
1352
    key: Buffer.from(publicKey, 'base64url'),
1353
    type: 'spki' as const,
1354
    format: 'der' as const,
1355
  };
1356
  return verify(
1357
    null,
1358
    Buffer.from(canonicalize(unsigned(value))),
1359
    key,
1360
    Buffer.from(parsed.data.value, 'base64url'),
1361
  );
1362
}