@siduri-x/core 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,6 @@ describe('ActionPolicyEngine Boundary', () => {
22
22
  },
23
23
  conversation: {
24
24
  channel: 'direct',
25
- audienceId: 'audience-direct',
26
25
  correlationId: 'corr-1',
27
26
  },
28
27
  };
@@ -14,7 +14,6 @@ describe('Adversarial Hardening Verification Suite (Phase 3)', () => {
14
14
  },
15
15
  conversation: {
16
16
  channel: 'private',
17
- audienceId: 'audience-owner',
18
17
  correlationId: 'corr-adv-1',
19
18
  },
20
19
  };
@@ -29,7 +28,6 @@ describe('Adversarial Hardening Verification Suite (Phase 3)', () => {
29
28
  },
30
29
  conversation: {
31
30
  channel: 'public',
32
- audienceId: 'audience-public',
33
31
  correlationId: 'corr-adv-2',
34
32
  },
35
33
  };
@@ -86,7 +84,7 @@ describe('Adversarial Hardening Verification Suite (Phase 3)', () => {
86
84
  ...baseOwnerContext,
87
85
  companionId: 'companion-A',
88
86
  });
89
- expect(mockMemory.searchClaims).toHaveBeenCalledWith('Query', expect.objectContaining({ channel: 'private', audienceId: 'audience-owner' }), 5);
87
+ expect(mockMemory.searchClaims).toHaveBeenCalledWith('Query', expect.objectContaining({ limit: 5 }), 5);
90
88
  });
91
89
  });
92
90
  // INVARIANT 2: Authority & Request Boundary
@@ -378,41 +376,39 @@ describe('Adversarial Hardening Verification Suite (Phase 3)', () => {
378
376
  describe('Invariant 8: Response Gating Evidence Admissibility Semantics', () => {
379
377
  test('gate strictly enforces evidence admissibility and disclosure without claiming unverified factuality', () => {
380
378
  const gating = new index_1.ResponseGatingEngine();
381
- const publicEvidence = {
379
+ const validEvidence = {
382
380
  evidenceId: 'ev-pub-1',
383
381
  sourceId: 'src-facts',
384
382
  origin: 'knowledge',
385
383
  trust: 'configured',
386
384
  sensitivity: 'public',
387
- allowedAudiences: ['audience-public'],
388
385
  companionId: 'companion-adv',
389
386
  correlationId: 'corr-adv-1',
390
387
  createdAt: new Date().toISOString(),
391
388
  };
392
- const privateEvidence = {
393
- evidenceId: 'ev-priv-1',
389
+ const foreignCompanionEvidence = {
390
+ evidenceId: 'ev-foreign-1',
394
391
  sourceId: 'src-secrets',
395
392
  origin: 'knowledge',
396
393
  trust: 'configured',
397
394
  sensitivity: 'restricted',
398
- allowedAudiences: ['audience-owner'],
399
- companionId: 'companion-adv',
395
+ companionId: 'foreign-companion',
400
396
  correlationId: 'corr-adv-1',
401
397
  createdAt: new Date().toISOString(),
402
398
  };
403
- // Staged for public channel with both public and restricted evidence attached
399
+ // Staged for companion-adv with both valid and foreign-companion evidence attached
404
400
  const staged = gating.stageResponse({
405
- requestContext: baseViewerContext, // Public channel
401
+ requestContext: baseOwnerContext,
406
402
  candidateSpeech: 'Siduri was created in 1840 by aliens.',
407
403
  candidateLanguage: 'en',
408
- evidenceRecords: [publicEvidence, privateEvidence],
404
+ evidenceRecords: [validEvidence, foreignCompanionEvidence],
409
405
  });
410
- const evaluation = gating.evaluateGate(staged, [publicEvidence, privateEvidence]);
406
+ const evaluation = gating.evaluateGate(staged, [validEvidence, foreignCompanionEvidence]);
411
407
  expect(evaluation.admissible).toBe(true);
412
408
  expect(evaluation.reasonCode).toBe('APPROVED_DIRECT');
413
- // Public evidence admitted, restricted private evidence excluded from public emission
409
+ // Valid companion evidence admitted, foreign companion evidence excluded by isolation boundary
414
410
  expect(evaluation.filteredEvidenceIds).toEqual(['ev-pub-1']);
415
- expect(evaluation.filteredEvidenceIds).not.toContain('ev-priv-1');
411
+ expect(evaluation.filteredEvidenceIds).not.toContain('ev-foreign-1');
416
412
  });
417
413
  });
418
414
  // INVARIANT 9: Full-Field Tamper-Evident Audit Trail
@@ -24,7 +24,6 @@ describe('AuthorizationCapability Cryptographic & Tamper Review', () => {
24
24
  },
25
25
  conversation: {
26
26
  channel: 'direct',
27
- audienceId: 'aud-alpha',
28
27
  correlationId: 'corr-999',
29
28
  },
30
29
  };
@@ -9,8 +9,6 @@ async function retrieveRuntimeContext(params) {
9
9
  const { companionId, perceivedText, requestContext, role, isContextObject, shouldQueryKnowledge, knowledge, memory, } = params;
10
10
  const queryOptions = isContextObject
11
11
  ? {
12
- channel: requestContext.conversation.channel,
13
- audienceId: requestContext.conversation.audienceId,
14
12
  limit: 5,
15
13
  }
16
14
  : role;
package/dist/context.d.ts CHANGED
@@ -9,7 +9,6 @@ export interface ConversationContext {
9
9
  correlationId: string;
10
10
  sessionId?: string;
11
11
  channel?: string;
12
- audienceId?: string;
13
12
  [key: string]: unknown;
14
13
  }
15
14
  export type SubjectKind = 'actor' | 'companion' | 'configured';
@@ -27,7 +26,7 @@ export interface RequestContext {
27
26
  metadata?: Record<string, unknown>;
28
27
  }
29
28
  export type DiagnosticCode = 'legacy_role_removed' | 'anonymous_session_generated' | 'companion_default_mapped_for_bootstrap' | 'actor_scoped_subject_mapped';
30
- export type ContextErrorCode = 'MISSING_CONTEXT' | 'INVALID_CONTEXT' | 'FORBIDDEN_CONTEXT' | 'LEGACY_PERSONAL_AUDIENCE' | 'AMBIGUOUS_CONTEXT' | 'UNAUTHORIZED_CAPABILITY';
29
+ export type ContextErrorCode = 'MISSING_CONTEXT' | 'INVALID_CONTEXT' | 'FORBIDDEN_CONTEXT' | 'AMBIGUOUS_CONTEXT' | 'UNAUTHORIZED_CAPABILITY';
31
30
  export interface ContextError {
32
31
  code: ContextErrorCode;
33
32
  message?: string;
@@ -33,7 +33,6 @@ describe('T5 ExperienceDispatcher Contract Suite', () => {
33
33
  companionId: 'companion-a',
34
34
  correlationId: 'corr-1',
35
35
  channel: 'public',
36
- audienceId: 'audience-public',
37
36
  speech: 'Hello dispatch',
38
37
  language: 'en',
39
38
  });
@@ -50,7 +49,6 @@ describe('T5 ExperienceDispatcher Contract Suite', () => {
50
49
  companionId: 'companion-a',
51
50
  correlationId: 'corr-1',
52
51
  channel: 'public',
53
- audienceId: 'audience-public',
54
52
  speech: 'Hello empty',
55
53
  });
56
54
  const summary = await emptyDispatcher.dispatchEvents(events);
@@ -16,13 +16,12 @@ export interface EvidenceRecord {
16
16
  expiresAt?: string;
17
17
  trust: EvidenceTrust;
18
18
  sensitivity?: EvidenceSensitivity;
19
- allowedAudiences?: string[];
20
19
  companionId: string;
21
20
  correlationId: string;
22
21
  [key: string]: unknown;
23
22
  }
24
23
  export type ResponseApprovalStatus = 'STAGED' | 'APPROVED' | 'REJECTED' | 'EXPIRED' | 'EMITTED';
25
- export type ResponseGateReasonCode = 'APPROVED_DIRECT' | 'APPROVAL_REQUIRED' | 'UNKNOWN_APPROVAL_ID' | 'APPROVAL_ID_MISMATCH' | 'COMPANION_MISMATCH' | 'AUDIENCE_MISMATCH' | 'EVIDENCE_EXPIRED' | 'EVIDENCE_SENSITIVITY_EXCLUDED' | 'UNRESOLVED_LOW_CONFIDENCE' | 'EMPTY_SPEECH' | 'PROPOSAL_VALIDATION_FAILED' | 'EXPLICITLY_REJECTED';
24
+ export type ResponseGateReasonCode = 'APPROVED_DIRECT' | 'APPROVAL_REQUIRED' | 'UNKNOWN_APPROVAL_ID' | 'APPROVAL_ID_MISMATCH' | 'COMPANION_MISMATCH' | 'EVIDENCE_EXPIRED' | 'EVIDENCE_SENSITIVITY_EXCLUDED' | 'UNRESOLVED_LOW_CONFIDENCE' | 'EMPTY_SPEECH' | 'PROPOSAL_VALIDATION_FAILED' | 'EXPLICITLY_REJECTED';
26
25
  export interface ResponseCitation {
27
26
  sourceId: string;
28
27
  documentId?: string;
@@ -35,7 +34,6 @@ export interface StagedResponsePlan {
35
34
  companionId: string;
36
35
  correlationId: string;
37
36
  channel?: string;
38
- audienceId?: string;
39
37
  speech: string;
40
38
  language: string;
41
39
  evidenceIds: string[];
@@ -63,7 +61,6 @@ export interface ResponseGateEvaluation {
63
61
  export interface EvidenceFilterOptions {
64
62
  companionId: string;
65
63
  channel?: string;
66
- audienceId?: string;
67
64
  now?: string | Date;
68
65
  [key: string]: unknown;
69
66
  }
package/dist/evidence.js CHANGED
@@ -19,28 +19,8 @@ function filterEvidenceRecords(records, options) {
19
19
  continue;
20
20
  }
21
21
  }
22
- // 3. Optional audience intersection (audience-public is accessible everywhere)
23
- if (options.audienceId &&
24
- record.allowedAudiences &&
25
- record.allowedAudiences.length > 0 &&
26
- !record.allowedAudiences.includes('audience-public') &&
27
- !record.allowedAudiences.includes(options.audienceId)) {
28
- excluded.push({ record, reason: 'audience_not_allowed' });
29
- continue;
30
- }
31
- // 4. Optional channel sensitivity policy (if channel explicitly specified)
32
- if (options.channel === 'public') {
33
- if (record.sensitivity && record.sensitivity !== 'public') {
34
- excluded.push({ record, reason: 'sensitivity_private_in_public_channel' });
35
- continue;
36
- }
37
- }
38
- else if (options.channel === 'direct') {
39
- if (record.sensitivity === 'restricted') {
40
- excluded.push({ record, reason: 'sensitivity_restricted_in_direct_channel' });
41
- continue;
42
- }
43
- }
22
+ // In single-owner architecture, memory and evidence are partitioned strictly
23
+ // by companion boundary (companionId) and temporal expiration.
44
24
  admitted.push(record);
45
25
  }
46
26
  return { admitted, excluded };
@@ -8,7 +8,6 @@ describe('T4 Evidence & Disclosure Core Contract', () => {
8
8
  origin: 'knowledge',
9
9
  trust: 'configured',
10
10
  sensitivity: 'public',
11
- allowedAudiences: ['audience-public'],
12
11
  companionId: 'companion-a',
13
12
  correlationId: 'corr-1',
14
13
  createdAt: new Date(Date.now() - 5000).toISOString(),
@@ -21,7 +20,6 @@ describe('T4 Evidence & Disclosure Core Contract', () => {
21
20
  const options = {
22
21
  companionId: 'companion-a',
23
22
  channel: 'public',
24
- audienceId: 'audience-public',
25
23
  };
26
24
  const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, options);
27
25
  expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-mine']);
@@ -40,7 +38,6 @@ describe('T4 Evidence & Disclosure Core Contract', () => {
40
38
  const options = {
41
39
  companionId: 'companion-a',
42
40
  channel: 'public',
43
- audienceId: 'audience-public',
44
41
  };
45
42
  const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, options);
46
43
  expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-valid']);
@@ -51,51 +48,28 @@ describe('T4 Evidence & Disclosure Core Contract', () => {
51
48
  }),
52
49
  ]);
53
50
  });
54
- test('audience intersection excludes non-matching audiences', () => {
51
+ test('single-owner companion admits valid evidence without multi-audience filtering', () => {
55
52
  const records = [
56
- { ...baseRecord, evidenceId: 'ev-public', allowedAudiences: ['audience-public'] },
57
- { ...baseRecord, evidenceId: 'ev-direct-only', allowedAudiences: ['audience-direct-a'] },
53
+ { ...baseRecord, evidenceId: 'ev-public' },
54
+ { ...baseRecord, evidenceId: 'ev-direct-only' },
58
55
  ];
59
56
  const options = {
60
57
  companionId: 'companion-a',
61
- channel: 'public',
62
- audienceId: 'audience-public',
63
58
  };
64
59
  const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, options);
65
- expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-public']);
66
- expect(excluded).toEqual([
67
- expect.objectContaining({
68
- record: expect.objectContaining({ evidenceId: 'ev-direct-only' }),
69
- reason: 'audience_not_allowed',
70
- }),
71
- ]);
72
- });
73
- test('sensitivity policy excludes private and restricted evidence from public channels', () => {
74
- const records = [
75
- { ...baseRecord, evidenceId: 'ev-pub', sensitivity: 'public', allowedAudiences: ['audience-public'] },
76
- { ...baseRecord, evidenceId: 'ev-priv', sensitivity: 'private', allowedAudiences: ['audience-public'] },
77
- { ...baseRecord, evidenceId: 'ev-rest', sensitivity: 'restricted', allowedAudiences: ['audience-public'] },
78
- ];
79
- const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, {
80
- companionId: 'companion-a',
81
- channel: 'public',
82
- audienceId: 'audience-public',
83
- });
84
- expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-pub']);
85
- expect(excluded.map((e) => e.record.evidenceId)).toEqual(['ev-priv', 'ev-rest']);
60
+ expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-public', 'ev-direct-only']);
61
+ expect(excluded).toEqual([]);
86
62
  });
87
- test('direct channel permits private sensitivity but excludes restricted', () => {
63
+ test('single-owner companion admits private and restricted sensitivity for companion owner', () => {
88
64
  const records = [
89
- { ...baseRecord, evidenceId: 'ev-pub', sensitivity: 'public', allowedAudiences: ['audience-direct-a'] },
90
- { ...baseRecord, evidenceId: 'ev-priv', sensitivity: 'private', allowedAudiences: ['audience-direct-a'] },
91
- { ...baseRecord, evidenceId: 'ev-rest', sensitivity: 'restricted', allowedAudiences: ['audience-direct-a'] },
65
+ { ...baseRecord, evidenceId: 'ev-pub', sensitivity: 'public' },
66
+ { ...baseRecord, evidenceId: 'ev-priv', sensitivity: 'private' },
67
+ { ...baseRecord, evidenceId: 'ev-rest', sensitivity: 'restricted' },
92
68
  ];
93
69
  const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(records, {
94
70
  companionId: 'companion-a',
95
- channel: 'direct',
96
- audienceId: 'audience-direct-a',
97
71
  });
98
- expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-pub', 'ev-priv']);
99
- expect(excluded.map((e) => e.record.evidenceId)).toEqual(['ev-rest']);
72
+ expect(admitted.map((e) => e.evidenceId)).toEqual(['ev-pub', 'ev-priv', 'ev-rest']);
73
+ expect(excluded).toEqual([]);
100
74
  });
101
75
  });
@@ -13,7 +13,6 @@ async function emitExperienceEvents(params) {
13
13
  companionId,
14
14
  correlationId: requestContext.conversation.correlationId,
15
15
  channel: requestContext.conversation?.channel,
16
- audienceId: requestContext.conversation?.audienceId,
17
16
  speech,
18
17
  language: language || 'ja',
19
18
  evidenceIds: gateEval.filteredEvidenceIds,
@@ -7,7 +7,6 @@ export interface ExperienceEvent {
7
7
  responseId: string;
8
8
  correlationId: string;
9
9
  channel?: string;
10
- audienceId?: string;
11
10
  approval: 'APPROVED';
12
11
  kind: ExperienceEventKind;
13
12
  lifecycle: ExperienceEventLifecycle;
@@ -39,7 +38,6 @@ export interface CreateExperienceEventsOptions {
39
38
  companionId: string;
40
39
  correlationId: string;
41
40
  channel?: string;
42
- audienceId?: string;
43
41
  speech: string;
44
42
  language?: string;
45
43
  evidenceIds?: string[];
@@ -17,7 +17,6 @@ function createExperienceEvents(options) {
17
17
  responseId: options.responseId,
18
18
  correlationId: options.correlationId,
19
19
  channel: options.channel,
20
- audienceId: options.audienceId,
21
20
  approval: 'APPROVED',
22
21
  kind: 'voice',
23
22
  lifecycle: 'STARTED',
@@ -35,7 +34,6 @@ function createExperienceEvents(options) {
35
34
  responseId: options.responseId,
36
35
  correlationId: options.correlationId,
37
36
  channel: options.channel,
38
- audienceId: options.audienceId,
39
37
  approval: 'APPROVED',
40
38
  kind: 'avatar',
41
39
  lifecycle: 'STARTED',
@@ -62,9 +60,6 @@ function validateExperienceEvent(event) {
62
60
  return { valid: false, error: 'Missing or invalid responseId' };
63
61
  if (!e.correlationId || typeof e.correlationId !== 'string')
64
62
  return { valid: false, error: 'Missing or invalid correlationId' };
65
- if (e.audienceId !== undefined && typeof e.audienceId !== 'string') {
66
- return { valid: false, error: 'Invalid audienceId: must be a string' };
67
- }
68
63
  if (e.approval !== 'APPROVED')
69
64
  return { valid: false, error: 'Event approval must be APPROVED' };
70
65
  if (!['voice', 'caption', 'avatar', 'platform_action'].includes(e.kind)) {
@@ -7,7 +7,6 @@ describe('T5 Experience Event Contract Suite', () => {
7
7
  companionId: 'companion-a',
8
8
  correlationId: 'corr-123',
9
9
  channel: 'public',
10
- audienceId: 'audience-public',
11
10
  speech: 'Hello world',
12
11
  language: 'en',
13
12
  evidenceIds: ['ev-1'],
@@ -52,8 +51,5 @@ describe('T5 Experience Event Contract Suite', () => {
52
51
  expect((0, experience_1.validateExperienceEvent)(missingCompanion).valid).toBe(false);
53
52
  const missingResponseId = { ...events[0], responseId: '' };
54
53
  expect((0, experience_1.validateExperienceEvent)(missingResponseId).valid).toBe(false);
55
- const withoutAudience = { ...events[0] };
56
- delete withoutAudience.audienceId;
57
- expect((0, experience_1.validateExperienceEvent)(withoutAudience).valid).toBe(true);
58
54
  });
59
55
  });
package/dist/gating.d.ts CHANGED
@@ -18,7 +18,6 @@ export interface ApproveResponseOptions {
18
18
  responseId: string;
19
19
  companionId: string;
20
20
  correlationId: string;
21
- audienceId?: string;
22
21
  }
23
22
  export interface RejectResponseOptions {
24
23
  responseId: string;
package/dist/gating.js CHANGED
@@ -40,7 +40,6 @@ class ResponseGatingEngine {
40
40
  companionId: requestContext.companionId,
41
41
  correlationId: requestContext.conversation.correlationId,
42
42
  channel: requestContext.conversation?.channel,
43
- audienceId: requestContext.conversation?.audienceId,
44
43
  speech: options.candidateSpeech,
45
44
  language: options.candidateLanguage,
46
45
  evidenceIds,
@@ -90,7 +89,6 @@ class ResponseGatingEngine {
90
89
  const { admitted, excluded } = (0, evidence_1.filterEvidenceRecords)(attachedEvidence, {
91
90
  companionId: staged.companionId,
92
91
  channel: staged.channel,
93
- audienceId: staged.audienceId,
94
92
  now,
95
93
  });
96
94
  // If any evidence attached to this plan violated disclosure in this channel, exclude it
@@ -14,7 +14,6 @@ describe('T4 Response Gating & Staged Approval Suite', () => {
14
14
  },
15
15
  conversation: {
16
16
  channel: 'public',
17
- audienceId: 'audience-public',
18
17
  correlationId: 'corr-gate-1',
19
18
  },
20
19
  };
@@ -28,7 +27,6 @@ describe('T4 Response Gating & Staged Approval Suite', () => {
28
27
  origin: 'knowledge',
29
28
  trust: 'configured',
30
29
  sensitivity: 'public',
31
- allowedAudiences: ['audience-public'],
32
30
  companionId: 'companion-a',
33
31
  correlationId: 'corr-gate-1',
34
32
  createdAt: new Date().toISOString(),
@@ -56,7 +54,6 @@ describe('T4 Response Gating & Staged Approval Suite', () => {
56
54
  origin: 'ocr',
57
55
  trust: 'untrusted',
58
56
  sensitivity: 'public',
59
- allowedAudiences: ['audience-public'],
60
57
  companionId: 'companion-a',
61
58
  correlationId: 'corr-gate-2',
62
59
  createdAt: new Date().toISOString(),
@@ -162,28 +159,27 @@ describe('T4 Response Gating & Staged Approval Suite', () => {
162
159
  expect(approveRes.success).toBe(false);
163
160
  expect(approveRes.reason).toBe('EVIDENCE_EXPIRED');
164
161
  });
165
- test('private evidence is filtered out and absent from public citations/evidence list', () => {
166
- const privateEvidence = {
167
- evidenceId: 'ev-priv-1',
162
+ test('foreign companion evidence is filtered out and absent from citations/evidence list', () => {
163
+ const foreignEvidence = {
164
+ evidenceId: 'ev-foreign-1',
168
165
  sourceId: 'src-secret',
169
166
  origin: 'knowledge',
170
167
  trust: 'configured',
171
168
  sensitivity: 'private',
172
- allowedAudiences: ['audience-direct-a'],
173
- companionId: 'companion-a',
169
+ companionId: 'companion-b',
174
170
  correlationId: 'corr-gate-1',
175
171
  createdAt: new Date().toISOString(),
176
172
  };
177
173
  const staged = engine.stageResponse({
178
- requestContext: validPublicContext, // public channel
179
- candidateSpeech: 'Public response text',
174
+ requestContext: validPublicContext, // companion-a
175
+ candidateSpeech: 'Response text',
180
176
  candidateLanguage: 'en',
181
- evidenceRecords: [privateEvidence],
177
+ evidenceRecords: [foreignEvidence],
182
178
  citations: [{ sourceId: 'src-secret' }],
183
179
  });
184
- const evalRes = engine.evaluateGate(staged, [privateEvidence]);
180
+ const evalRes = engine.evaluateGate(staged, [foreignEvidence]);
185
181
  expect(evalRes.admissible).toBe(true);
186
- // Private evidence and its citation must be stripped from public output metadata
182
+ // Foreign companion evidence and its citation must be stripped due to companion isolation
187
183
  expect(evalRes.filteredEvidenceIds).toEqual([]);
188
184
  expect(evalRes.filteredCitations).toEqual([]);
189
185
  });
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export * from './action-executor';
22
22
  export * from './experience-emitter';
23
23
  export * from './response-envelope';
24
24
  export * from './session-history';
25
+ export * from './schema-validator';
25
26
  import { EvidenceRecord } from './evidence';
26
27
  import { ActionIntent } from './action';
27
28
  import { RequestContext } from './context';
package/dist/index.js CHANGED
@@ -39,5 +39,6 @@ __exportStar(require("./action-executor"), exports);
39
39
  __exportStar(require("./experience-emitter"), exports);
40
40
  __exportStar(require("./response-envelope"), exports);
41
41
  __exportStar(require("./session-history"), exports);
42
+ __exportStar(require("./schema-validator"), exports);
42
43
  // Mouth (Communication & Output Delivery)
43
44
  __exportStar(require("./mouth-types"), exports);
@@ -13,7 +13,6 @@ describe('IntentClassifier', () => {
13
13
  },
14
14
  conversation: {
15
15
  channel: 'direct',
16
- audienceId: 'aud-1',
17
16
  correlationId: 'corr-1',
18
17
  },
19
18
  };
@@ -26,7 +26,6 @@ async function settleMemoryProposals(params) {
26
26
  companionId,
27
27
  actorId: requestContext.actor.actorId,
28
28
  channel: requestContext.conversation.channel,
29
- audienceId: requestContext.conversation.audienceId,
30
29
  },
31
30
  };
32
31
  await memory.addSourceEvent(sourceEvent);
@@ -47,7 +46,6 @@ async function settleMemoryProposals(params) {
47
46
  userConfirmation: 'none',
48
47
  sensitivity: claim.sensitivity ||
49
48
  (requestContext.conversation?.channel === 'public' ? 'public' : 'private'),
50
- allowedAudiences: claim.allowedAudiences || (requestContext.conversation?.audienceId ? [requestContext.conversation.audienceId] : undefined),
51
49
  });
52
50
  createdMemoryProposals.push(proposal);
53
51
  }
@@ -63,7 +61,6 @@ async function settleMemoryProposals(params) {
63
61
  sourceEventId: sourceEventId || p.sourceEventId,
64
62
  claimType: p.claimType || 'semantic',
65
63
  sensitivity: p.sensitivity || 'private',
66
- allowedAudiences: p.allowedAudiences || (requestContext.conversation?.audienceId ? [requestContext.conversation.audienceId] : undefined),
67
64
  });
68
65
  createdMemoryProposals.push(proposal);
69
66
  }
@@ -23,7 +23,6 @@ describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
23
23
  },
24
24
  conversation: {
25
25
  channel: 'direct',
26
- audienceId: 'aud-direct',
27
26
  correlationId: 'corr-perc-1',
28
27
  },
29
28
  };
@@ -89,7 +88,7 @@ describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
89
88
  capabilities: ['chat:public'],
90
89
  authenticated: true,
91
90
  },
92
- conversation: { channel: 'direct', audienceId: 'aud-alice', correlationId: 'c1' },
91
+ conversation: { channel: 'direct', correlationId: 'c1' },
93
92
  };
94
93
  const bobContext = {
95
94
  companionId: 'comp-multi',
@@ -100,7 +99,7 @@ describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
100
99
  capabilities: ['chat:public'],
101
100
  authenticated: false,
102
101
  },
103
- conversation: { channel: 'public', audienceId: 'aud-public', correlationId: 'c2' },
102
+ conversation: { channel: 'public', correlationId: 'c2' },
104
103
  };
105
104
  await runtime.handleUserMessage('Alice secret message', aliceContext);
106
105
  await runtime.handleUserMessage('Bob public query', bobContext);
@@ -122,7 +121,6 @@ describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
122
121
  origin: 'knowledge',
123
122
  trust: 'configured',
124
123
  sensitivity: 'public',
125
- allowedAudiences: ['audience-public'],
126
124
  companionId: 'comp-native-ev',
127
125
  correlationId: 'corr-test',
128
126
  createdAt: new Date().toISOString(),
@@ -32,11 +32,8 @@ async function compilePrompts(params) {
32
32
  // Compile Behavior with neutral context metadata
33
33
  const behaviorInjections = behavior && typeof behavior.compile === 'function'
34
34
  ? await behavior.compile({
35
- activeRole: role,
36
35
  directives: activeDirectives,
37
36
  companionId,
38
- channel: requestContext.conversation.channel,
39
- audienceId: requestContext.conversation.audienceId,
40
37
  actorId: requestContext.actor.actorId,
41
38
  })
42
39
  : '';
@@ -13,7 +13,6 @@ describe('PromptCompiler', () => {
13
13
  },
14
14
  conversation: {
15
15
  channel: 'direct',
16
- audienceId: 'aud-1',
17
16
  correlationId: 'corr-1',
18
17
  },
19
18
  };
@@ -16,7 +16,6 @@ export interface MemoryProposal {
16
16
  provenance?: string;
17
17
  claimType?: ClaimType;
18
18
  sensitivity?: string;
19
- allowedAudiences?: string[];
20
19
  sourceEventId?: string;
21
20
  }
22
21
  export interface BehaviorProposal {
@@ -66,4 +66,30 @@ describe('SiduriRuntime Facade Methods & Delegation', () => {
66
66
  await runtime.resetMemory();
67
67
  expect(mockMemory.resetMemory).toHaveBeenCalled();
68
68
  });
69
+ test('configures SqliteActionStore when actionStore is sqlite', () => {
70
+ const runtime = new runtime_1.SiduriRuntime('comp-sqlite', {
71
+ id: 'comp-sqlite',
72
+ name: 'Sqlite Test',
73
+ actionStore: 'sqlite',
74
+ });
75
+ expect(runtime.actionPolicy.getStore()).toBeDefined();
76
+ // Verify it is an instance of SqliteActionStore
77
+ expect(runtime.actionPolicy.getStore().constructor.name).toBe('SqliteActionStore');
78
+ });
79
+ test('accepts custom actionStore via RuntimeOrgans', () => {
80
+ const customStore = {
81
+ recordExecution: jest.fn(),
82
+ getExecution: jest.fn(),
83
+ updateExecution: jest.fn(),
84
+ recordApproval: jest.fn(),
85
+ getApproval: jest.fn(),
86
+ recordAudit: jest.fn(),
87
+ getAuditLog: jest.fn(),
88
+ verifyAuditChain: jest.fn(),
89
+ };
90
+ const runtime = new runtime_1.SiduriRuntime('comp-custom', { id: 'comp-custom', name: 'Custom' }, {
91
+ actionStore: customStore,
92
+ });
93
+ expect(runtime.actionPolicy.getStore()).toBe(customStore);
94
+ });
69
95
  });
package/dist/runtime.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BrainOrgan, MemoryOrgan, VoiceOrgan, KnowledgeOrgan, VisionOrgan, BehaviorOrgan, BodyOrgan, HandsOrgan, EarOrgan, ObservationOrgan, ObservationResult, Observation, Message, RequestContext, ActionPolicyEngine, ResponseGatingEngine, StageResponseOptions, ApproveResponseOptions, RejectResponseOptions, ExperienceDispatcher, ExperienceAdapter, OrganConfig, Claim, BehaviorDirective, StagedResponsePlan, ResponseGateEvaluation, EvidenceRecord, MouthOrgan, MouthUtterance, MouthMedium, FormattedMouthOutput, MouthStreamChunk, MouthChannel } from './index';
1
+ import { BrainOrgan, MemoryOrgan, VoiceOrgan, KnowledgeOrgan, VisionOrgan, BehaviorOrgan, BodyOrgan, HandsOrgan, EarOrgan, ObservationOrgan, ObservationResult, Observation, Message, RequestContext, ActionPolicyEngine, ActionStore, ResponseGatingEngine, StageResponseOptions, ApproveResponseOptions, RejectResponseOptions, ExperienceDispatcher, ExperienceAdapter, OrganConfig, Claim, BehaviorDirective, StagedResponsePlan, ResponseGateEvaluation, EvidenceRecord, MouthOrgan, MouthUtterance, MouthMedium, FormattedMouthOutput, MouthStreamChunk, MouthChannel } from './index';
2
2
  export interface SiduriRuntimeConfig {
3
3
  name: string;
4
4
  brain?: OrganConfig | Record<string, unknown>;
@@ -13,6 +13,11 @@ export interface SiduriRuntimeConfig {
13
13
  observation?: OrganConfig | Record<string, unknown>;
14
14
  mouth?: OrganConfig | Record<string, unknown>;
15
15
  actionPolicy?: Record<string, unknown>;
16
+ actionStore?: 'in-memory' | 'sqlite' | {
17
+ type: 'sqlite' | 'in-memory';
18
+ dbPath?: string;
19
+ };
20
+ actionStorePath?: string;
16
21
  [key: string]: unknown;
17
22
  }
18
23
  export interface RuntimeOrgans {
@@ -27,6 +32,7 @@ export interface RuntimeOrgans {
27
32
  ear?: EarOrgan;
28
33
  observation?: ObservationOrgan;
29
34
  mouth?: MouthOrgan;
35
+ actionStore?: ActionStore;
30
36
  actionPolicy?: ActionPolicyEngine;
31
37
  }
32
38
  export interface CompanionPerception {
package/dist/runtime.js CHANGED
@@ -57,7 +57,17 @@ class SiduriRuntime {
57
57
  this.observation = organs.observation;
58
58
  this.mouth = organs.mouth;
59
59
  this.gating = new index_1.ResponseGatingEngine();
60
- this.actionPolicy = organs.actionPolicy || new index_1.ActionPolicyEngine();
60
+ let actionStore = organs.actionStore;
61
+ if (!actionStore) {
62
+ const storeOpt = config.actionStore;
63
+ const storePath = config.actionStorePath || (typeof storeOpt === 'object' ? storeOpt.dbPath : undefined);
64
+ if (storeOpt === 'sqlite' || (typeof storeOpt === 'object' && storeOpt.type === 'sqlite') || storePath) {
65
+ actionStore = new index_1.SqliteActionStore({ dbPath: storePath });
66
+ }
67
+ }
68
+ this.actionPolicy = organs.actionPolicy || new index_1.ActionPolicyEngine({
69
+ store: actionStore,
70
+ });
61
71
  this.dispatcher = new index_1.ExperienceDispatcher();
62
72
  if (this.voice && typeof this.voice.handleEvent === 'function') {
63
73
  this.dispatcher.registerAdapter(this.voice);
@@ -214,7 +224,7 @@ class SiduriRuntime {
214
224
  // 1. Input validation, RequestContext synthesis, and Ear perception routing
215
225
  const input = await (0, input_normalizer_1.normalizeUserInput)(rawText, roleOrContext, history, this.id, this.ear);
216
226
  const sessionKey = input.requestContext.actor.sessionId ||
217
- input.requestContext.conversation.audienceId ||
227
+ input.requestContext.conversation.correlationId ||
218
228
  'default';
219
229
  const currentMessage = { role: 'user', content: input.perceivedText };
220
230
  const boundedSessionHistory = [...input.boundedHistory, currentMessage].slice(-20);
@@ -0,0 +1,9 @@
1
+ export declare class ConfigValidationError extends Error {
2
+ errors: string[];
3
+ constructor(errors: string[]);
4
+ }
5
+ /**
6
+ * Validates a companion configuration object against a JSON schema (draft-07 compatible).
7
+ * Throws ConfigValidationError if validation errors are detected.
8
+ */
9
+ export declare function validateCompanionConfig(config: unknown, schema: any, path?: string): void;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigValidationError = void 0;
4
+ exports.validateCompanionConfig = validateCompanionConfig;
5
+ class ConfigValidationError extends Error {
6
+ errors;
7
+ constructor(errors) {
8
+ super(`Siduri configuration validation failed:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
9
+ this.name = 'ConfigValidationError';
10
+ this.errors = errors;
11
+ }
12
+ }
13
+ exports.ConfigValidationError = ConfigValidationError;
14
+ /**
15
+ * Validates a companion configuration object against a JSON schema (draft-07 compatible).
16
+ * Throws ConfigValidationError if validation errors are detected.
17
+ */
18
+ function validateCompanionConfig(config, schema, path = '$') {
19
+ const errors = [];
20
+ function validateNode(value, nodeSchema, curPath) {
21
+ if (!nodeSchema || typeof nodeSchema !== 'object')
22
+ return;
23
+ // Type validation
24
+ if (nodeSchema.type !== undefined) {
25
+ const type = nodeSchema.type;
26
+ if (type === 'object') {
27
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
28
+ errors.push(`${curPath}: expected object, received ${value === null ? 'null' : Array.isArray(value) ? 'array' : typeof value}`);
29
+ return;
30
+ }
31
+ }
32
+ else if (type === 'array') {
33
+ if (!Array.isArray(value)) {
34
+ errors.push(`${curPath}: expected array, received ${typeof value}`);
35
+ return;
36
+ }
37
+ }
38
+ else if (type === 'string') {
39
+ if (typeof value !== 'string') {
40
+ errors.push(`${curPath}: expected string, received ${typeof value}`);
41
+ return;
42
+ }
43
+ }
44
+ else if (type === 'number') {
45
+ if (typeof value !== 'number' || Number.isNaN(value)) {
46
+ errors.push(`${curPath}: expected number, received ${typeof value}`);
47
+ return;
48
+ }
49
+ }
50
+ else if (type === 'integer') {
51
+ if (typeof value !== 'number' || !Number.isInteger(value)) {
52
+ errors.push(`${curPath}: expected integer, received ${typeof value}`);
53
+ return;
54
+ }
55
+ }
56
+ else if (type === 'boolean') {
57
+ if (typeof value !== 'boolean') {
58
+ errors.push(`${curPath}: expected boolean, received ${typeof value}`);
59
+ return;
60
+ }
61
+ }
62
+ }
63
+ // Enum validation
64
+ if (Array.isArray(nodeSchema.enum)) {
65
+ if (!nodeSchema.enum.includes(value)) {
66
+ errors.push(`${curPath}: invalid value ${JSON.stringify(value)}, expected one of: ${nodeSchema.enum.map((v) => JSON.stringify(v)).join(', ')}`);
67
+ return;
68
+ }
69
+ }
70
+ // Object properties validation
71
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
72
+ if (Array.isArray(nodeSchema.required)) {
73
+ for (const reqKey of nodeSchema.required) {
74
+ if (value[reqKey] === undefined) {
75
+ errors.push(`${curPath}.${reqKey}: is required`);
76
+ }
77
+ }
78
+ }
79
+ const definedProps = nodeSchema.properties || {};
80
+ if (nodeSchema.additionalProperties === false) {
81
+ for (const key of Object.keys(value)) {
82
+ // Allow $schema property at root level
83
+ if (curPath === '$' && key === '$schema')
84
+ continue;
85
+ if (!(key in definedProps)) {
86
+ errors.push(`${curPath}.${key}: unexpected property is not allowed`);
87
+ }
88
+ }
89
+ }
90
+ for (const [propName, propSchema] of Object.entries(definedProps)) {
91
+ if (value[propName] !== undefined) {
92
+ validateNode(value[propName], propSchema, `${curPath}.${propName}`);
93
+ }
94
+ }
95
+ }
96
+ // Array items validation
97
+ if (Array.isArray(value) && nodeSchema.items) {
98
+ value.forEach((item, index) => {
99
+ validateNode(item, nodeSchema.items, `${curPath}[${index}]`);
100
+ });
101
+ }
102
+ }
103
+ validateNode(config, schema, path);
104
+ if (errors.length > 0) {
105
+ throw new ConfigValidationError(errors);
106
+ }
107
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const schema_validator_1 = require("./schema-validator");
4
+ describe('validateCompanionConfig', () => {
5
+ const sampleSchema = {
6
+ type: 'object',
7
+ required: ['id', 'name', 'organs'],
8
+ additionalProperties: false,
9
+ properties: {
10
+ $schema: { type: 'string' },
11
+ id: { type: 'string' },
12
+ name: { type: 'string' },
13
+ organs: {
14
+ type: 'object',
15
+ additionalProperties: false,
16
+ properties: {
17
+ brain: {
18
+ type: 'object',
19
+ required: ['provider', 'model'],
20
+ properties: {
21
+ provider: {
22
+ type: 'string',
23
+ enum: ['openrouter', 'openai-compatible'],
24
+ },
25
+ model: { type: 'string' },
26
+ },
27
+ },
28
+ memory: {
29
+ type: 'object',
30
+ required: ['provider'],
31
+ properties: {
32
+ provider: {
33
+ type: 'string',
34
+ enum: ['postgres', 'in-memory', 'none'],
35
+ },
36
+ maxConnections: { type: 'number' },
37
+ },
38
+ },
39
+ },
40
+ },
41
+ },
42
+ };
43
+ test('accepts valid configuration matching schema', () => {
44
+ const validConfig = {
45
+ $schema: './siduri.schema.json',
46
+ id: 'companion-1',
47
+ name: 'Test Companion',
48
+ organs: {
49
+ brain: {
50
+ provider: 'openrouter',
51
+ model: 'gpt-4o',
52
+ },
53
+ },
54
+ };
55
+ expect(() => (0, schema_validator_1.validateCompanionConfig)(validConfig, sampleSchema)).not.toThrow();
56
+ });
57
+ test('throws ConfigValidationError if missing required root field', () => {
58
+ const invalidConfig = {
59
+ name: 'Missing Id and Organs',
60
+ };
61
+ expect(() => (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema)).toThrow(schema_validator_1.ConfigValidationError);
62
+ try {
63
+ (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema);
64
+ }
65
+ catch (err) {
66
+ expect(err.errors).toContain('$.id: is required');
67
+ expect(err.errors).toContain('$.organs: is required');
68
+ }
69
+ });
70
+ test('throws ConfigValidationError on unexpected property when additionalProperties is false', () => {
71
+ const invalidConfig = {
72
+ id: 'c-1',
73
+ name: 'Test',
74
+ organs: {},
75
+ extraField: 'not allowed',
76
+ };
77
+ expect(() => (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema)).toThrow(schema_validator_1.ConfigValidationError);
78
+ try {
79
+ (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema);
80
+ }
81
+ catch (err) {
82
+ expect(err.errors).toContain('$.extraField: unexpected property is not allowed');
83
+ }
84
+ });
85
+ test('throws ConfigValidationError on invalid enum value', () => {
86
+ const invalidConfig = {
87
+ id: 'c-1',
88
+ name: 'Test',
89
+ organs: {
90
+ brain: {
91
+ provider: 'invalid-brain-provider',
92
+ model: 'gpt-4',
93
+ },
94
+ },
95
+ };
96
+ expect(() => (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema)).toThrow(schema_validator_1.ConfigValidationError);
97
+ try {
98
+ (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema);
99
+ }
100
+ catch (err) {
101
+ expect(err.errors.some((e) => e.includes('invalid value "invalid-brain-provider"'))).toBe(true);
102
+ }
103
+ });
104
+ test('throws ConfigValidationError on invalid type', () => {
105
+ const invalidConfig = {
106
+ id: 12345, // should be string
107
+ name: 'Test',
108
+ organs: {
109
+ memory: {
110
+ provider: 'postgres',
111
+ maxConnections: 'ten', // should be number
112
+ },
113
+ },
114
+ };
115
+ expect(() => (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema)).toThrow(schema_validator_1.ConfigValidationError);
116
+ try {
117
+ (0, schema_validator_1.validateCompanionConfig)(invalidConfig, sampleSchema);
118
+ }
119
+ catch (err) {
120
+ expect(err.errors).toContain('$.id: expected string, received number');
121
+ expect(err.errors).toContain('$.organs.memory.maxConnections: expected number, received string');
122
+ }
123
+ });
124
+ });
@@ -210,7 +210,6 @@ describe('SqliteActionStore Implementation & Durability', () => {
210
210
  },
211
211
  conversation: {
212
212
  channel: 'direct',
213
- audienceId: 'aud-local',
214
213
  correlationId: 'corr-1',
215
214
  },
216
215
  };
@@ -4,12 +4,12 @@ export interface ExtractedTeaching {
4
4
  behaviorProposals: BehaviorProposal[];
5
5
  }
6
6
  /**
7
- * Deterministically extracts teaching candidates from user messages according to neutral T1/T2 contracts.
7
+ * Deterministically extracts teaching candidates from user messages according to single-owner model.
8
8
  *
9
9
  * Rules:
10
10
  * - Scoped to the requesting actor context (subject: `actor:${actorId}`), NEVER `primary_user`.
11
11
  * - Candidates are pending proposals only, never active/approved.
12
- * - Allowed audiences derive from the request conversation or policy context (e.g. direct audience).
12
+ * - In a single-owner companion, preferences apply across the companion instance without audience partitioning.
13
13
  * - Companion identity is isolated.
14
14
  */
15
15
  export declare function extractDeterministicTeaching(message: string, context?: RequestContext, sourceEventId?: string): ExtractedTeaching;
package/dist/teaching.js CHANGED
@@ -5,12 +5,12 @@ function cleanValue(value, limit = 160) {
5
5
  return value.replace(/\s+/g, ' ').replace(/^[ .,!?:;"']+|[ .,!?:;"']+$/g, '').slice(0, limit);
6
6
  }
7
7
  /**
8
- * Deterministically extracts teaching candidates from user messages according to neutral T1/T2 contracts.
8
+ * Deterministically extracts teaching candidates from user messages according to single-owner model.
9
9
  *
10
10
  * Rules:
11
11
  * - Scoped to the requesting actor context (subject: `actor:${actorId}`), NEVER `primary_user`.
12
12
  * - Candidates are pending proposals only, never active/approved.
13
- * - Allowed audiences derive from the request conversation or policy context (e.g. direct audience).
13
+ * - In a single-owner companion, preferences apply across the companion instance without audience partitioning.
14
14
  * - Companion identity is isolated.
15
15
  */
16
16
  function extractDeterministicTeaching(message, context, sourceEventId) {
@@ -23,7 +23,6 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
23
23
  const actorId = context?.actor?.actorId;
24
24
  const actorSubject = actorId ? `actor:${actorId}` : 'actor:anonymous';
25
25
  const companionId = context?.companionId || 'default';
26
- const defaultAudience = context?.conversation?.audienceId || (context?.conversation?.channel === 'direct' ? `audience-direct-${actorId}` : 'audience-public');
27
26
  const sensitivity = context?.conversation?.channel === 'public' ? 'public' : 'private';
28
27
  // 1. Companion's Name: "your name is X" / "you are called X"
29
28
  const companionNameMatch = text.match(/\b(?:your name is|you are called)\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
@@ -37,7 +36,6 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
37
36
  claimType: 'semantic',
38
37
  provenance: 'deterministic_teaching',
39
38
  sensitivity: 'public',
40
- allowedAudiences: ['audience-public'],
41
39
  sourceEventId,
42
40
  });
43
41
  behaviorProposals.push({
@@ -62,36 +60,14 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
62
60
  claimType: 'preference',
63
61
  provenance: 'deterministic_teaching',
64
62
  sensitivity,
65
- allowedAudiences: [defaultAudience],
66
63
  sourceEventId,
67
64
  });
68
65
  }
69
66
  // 3. Preferred Address / Call me X: "call me X"
70
- const callMeMatch = text.match(/\b(?:(?:from now on|only),?\s*)?call me\s+(.+?)(?:\s+(in private|privately|in public|publicly|everywhere|in direct conversations))?(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
67
+ const callMeMatch = text.match(/\b(?:(?:from now on|only),?\s*)?call me\s+(.+?)(?:\s+(?:in private|privately|in public|publicly|everywhere|in direct conversations))?(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
71
68
  if (callMeMatch) {
72
69
  const address = cleanValue(callMeMatch[1], 80);
73
- const scopePhrase = (callMeMatch[2] || '').toLowerCase();
74
- let claimAudiences = [defaultAudience];
75
- let claimSensitivity = sensitivity;
76
- let directiveInstruction = `Address ${actorSubject} as ${address}`;
77
- if (scopePhrase.includes('private') || scopePhrase.includes('privately')) {
78
- claimSensitivity = 'private';
79
- claimAudiences = [context?.conversation?.audienceId || `audience-private-${actorId}`];
80
- directiveInstruction += ' in private conversations';
81
- }
82
- else if (scopePhrase.includes('public') || scopePhrase.includes('publicly')) {
83
- claimSensitivity = 'public';
84
- claimAudiences = ['audience-public'];
85
- directiveInstruction += ' in public conversations';
86
- }
87
- else if (scopePhrase.includes('direct')) {
88
- claimSensitivity = 'private';
89
- claimAudiences = [context?.conversation?.audienceId || `audience-direct-${actorId}`];
90
- directiveInstruction += ' in direct conversations';
91
- }
92
- else {
93
- directiveInstruction += ' when addressing the actor';
94
- }
70
+ const directiveInstruction = `Address ${actorSubject} as ${address}`;
95
71
  claims.push({
96
72
  subject: actorSubject,
97
73
  predicate: 'preferred_address',
@@ -99,8 +75,7 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
99
75
  content: `The actor's preferred address is ${address}.`,
100
76
  claimType: 'relationship',
101
77
  provenance: 'deterministic_teaching',
102
- sensitivity: claimSensitivity,
103
- allowedAudiences: claimAudiences,
78
+ sensitivity,
104
79
  sourceEventId,
105
80
  });
106
81
  behaviorProposals.push({
@@ -125,7 +100,6 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
125
100
  claimType: 'relationship',
126
101
  provenance: 'deterministic_teaching',
127
102
  sensitivity: 'private',
128
- allowedAudiences: [defaultAudience],
129
103
  sourceEventId,
130
104
  });
131
105
  behaviorProposals.push({
@@ -151,7 +125,6 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
151
125
  claimType: 'preference',
152
126
  provenance: 'deterministic_teaching',
153
127
  sensitivity,
154
- allowedAudiences: [defaultAudience],
155
128
  sourceEventId,
156
129
  });
157
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siduri-x/core",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Core runtime types, evidence protocol, action dispatcher, capability validation, and SiduriRuntime protocol",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {