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

Viewing files at commit 922a6b480fb8Commit detailsView latest

tests/source-record.test.ts 120 lines · 4.5 KB · typescript
1
import { describe, expect, it } from 'vitest';
2
import {
3
  HOSTED_MIGRATIONS,
4
  buildSourceRecordEnvelope,
5
  shouldJournalSourceRecord,
6
} from '@openclasp/persistence';
7
import {
8
  LiveSessionStateRecordSchema,
9
  SourceRecordEnvelopeSchema,
10
  canonicalHash,
11
} from '@openclasp/protocol';
12
13
describe('production source record journal', () => {
14
  it('wraps a hosted record with explicit lineage and stable content integrity', () => {
15
    const payload = {
16
      interactionId: '11111111-1111-4111-8111-111111111111',
17
      agentId: 'agent:provider',
18
      outcome: 'success',
19
      completedAt: '2026-08-31T10:15:00.000Z',
20
      contributionMode: 'local_only',
21
    };
22
    const source = buildSourceRecordEnvelope({
23
      operatorId: 'operator:buyer',
24
      kind: 'completion_report',
25
      recordId: 'report:1',
26
      payload,
27
      metadata: {
28
        eventId: '22222222-2222-4222-8222-222222222222',
29
        ingestedAt: '2026-08-31T10:16:00.000Z',
30
      },
31
    });
32
33
    expect(SourceRecordEnvelopeSchema.parse(source)).toEqual(source);
34
    expect(source.payloadDigest).toBe(canonicalHash(payload));
35
    expect(source.reportedAt).toBe(payload.completedAt);
36
    expect(source.ingestedAt).toBe('2026-08-31T10:16:00.000Z');
37
    expect(source.entityRefs).toEqual({
38
      agentId: 'agent:provider',
39
      interactionId: payload.interactionId,
40
    });
41
    expect(source.learningScope).toBe('local_only');
42
    expect(source.retentionClass).toBe('audit');
43
    expect(source.provenance).toBe('observed');
44
    expect(source.visibility).toBe('shared_participants');
45
  });
46
47
  it('uses canonical payload digests and permits explicit collection metadata', () => {
48
    const base = {
49
      operatorId: 'operator:one',
50
      kind: 'agent_profile',
51
      recordId: 'agent:one',
52
      metadata: {
53
        eventId: '33333333-3333-4333-8333-333333333333',
54
        reportedAt: '2026-08-31T00:00:00.000Z',
55
        ingestedAt: '2026-08-31T00:00:01.000Z',
56
        provenance: 'operator_attested' as const,
57
        visibility: 'shared_participants' as const,
58
        entityRefs: { deploymentId: 'deployment:one' },
59
      },
60
    };
61
    const left = buildSourceRecordEnvelope({ ...base, payload: { b: 2, a: 1 } });
62
    const right = buildSourceRecordEnvelope({ ...base, payload: { a: 1, b: 2 } });
63
64
    expect(left.payloadDigest).toBe(right.payloadDigest);
65
    expect(left.retentionClass).toBe('account');
66
    expect(left.provenance).toBe('operator_attested');
67
    expect(left.visibility).toBe('shared_participants');
68
    expect(left.entityRefs.deploymentId).toBe('deployment:one');
69
  });
70
71
  it('rejects values that cannot be retained as JSON', () => {
72
    expect(() =>
73
      buildSourceRecordEnvelope({
74
        operatorId: 'operator:one',
75
        kind: 'event',
76
        recordId: 'event:one',
77
        payload: { invalid: undefined },
78
      }),
79
    ).toThrow();
80
  });
81
82
  it('keeps hosted migrations numbered, ordered, and uniquely named', () => {
83
    expect(HOSTED_MIGRATIONS.map((migration) => migration.version)).toEqual([1, 2]);
84
    expect(new Set(HOSTED_MIGRATIONS.map((migration) => migration.name)).size).toBe(
85
      HOSTED_MIGRATIONS.length,
86
    );
87
  });
88
89
  it('journals intelligence inputs but not high-volume operational projections', () => {
90
    expect(shouldJournalSourceRecord('completion_report')).toBe(true);
91
    expect(shouldJournalSourceRecord('interaction_feedback')).toBe(true);
92
    expect(shouldJournalSourceRecord('federated_interaction')).toBe(true);
93
    expect(shouldJournalSourceRecord('live_session_event')).toBe(true);
94
    expect(shouldJournalSourceRecord('live_session_state')).toBe(true);
95
    expect(shouldJournalSourceRecord('profile_delta')).toBe(true);
96
    expect(shouldJournalSourceRecord('presence')).toBe(false);
97
    expect(shouldJournalSourceRecord('profile')).toBe(false);
98
    expect(shouldJournalSourceRecord('feedback_request')).toBe(false);
99
  });
100
101
  it('keeps live-session state useful without retaining endpoints or raw errors', () => {
102
    const state = {
103
      interactionId: '11111111-1111-4111-8111-111111111111',
104
      initiatorAgentId: 'agent:buyer',
105
      responderAgentId: 'agent:provider',
106
      status: 'failed',
107
      expiresAt: '2026-08-31T10:30:00.000Z',
108
      createdAt: '2026-08-31T10:00:00.000Z',
109
      failureCode: 'session_failed',
110
    } as const;
111
112
    expect(LiveSessionStateRecordSchema.parse(state)).toEqual(state);
113
    expect(() =>
114
      LiveSessionStateRecordSchema.parse({ ...state, lastError: 'secret upstream response' }),
115
    ).toThrow();
116
    expect(() =>
117
      LiveSessionStateRecordSchema.parse({ ...state, initiatorEndpoint: 'https://private.test' }),
118
    ).toThrow();
119
  });
120
});