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

Viewing files at commit 68f53f7907caCommit detailsView latest

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