@agentplat/inference-control 0.3.0-beta.2 → 0.3.0-beta.4

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.
Files changed (150) hide show
  1. package/README.md +360 -0
  2. package/dist/anytime-semantic-guarantees.d.ts +216 -0
  3. package/dist/anytime-semantic-guarantees.d.ts.map +1 -0
  4. package/dist/anytime-semantic-guarantees.js +817 -0
  5. package/dist/anytime-semantic-guarantees.js.map +1 -0
  6. package/dist/assessor-ensemble-contracts.d.ts +145 -0
  7. package/dist/assessor-ensemble-contracts.d.ts.map +1 -0
  8. package/dist/assessor-ensemble-contracts.js +29 -0
  9. package/dist/assessor-ensemble-contracts.js.map +1 -0
  10. package/dist/assessor-ensemble-runtime.d.ts +55 -0
  11. package/dist/assessor-ensemble-runtime.d.ts.map +1 -0
  12. package/dist/assessor-ensemble-runtime.js +308 -0
  13. package/dist/assessor-ensemble-runtime.js.map +1 -0
  14. package/dist/assessor-ensemble-validation.d.ts +12 -0
  15. package/dist/assessor-ensemble-validation.d.ts.map +1 -0
  16. package/dist/assessor-ensemble-validation.js +156 -0
  17. package/dist/assessor-ensemble-validation.js.map +1 -0
  18. package/dist/assessor-ensemble.d.ts +4 -0
  19. package/dist/assessor-ensemble.d.ts.map +1 -0
  20. package/dist/assessor-ensemble.js +4 -0
  21. package/dist/assessor-ensemble.js.map +1 -0
  22. package/dist/cognitive-adapters.d.ts +92 -0
  23. package/dist/cognitive-adapters.d.ts.map +1 -0
  24. package/dist/cognitive-adapters.js +263 -0
  25. package/dist/cognitive-adapters.js.map +1 -0
  26. package/dist/context-integrity-analyzers.d.ts +35 -0
  27. package/dist/context-integrity-analyzers.d.ts.map +1 -0
  28. package/dist/context-integrity-analyzers.js +387 -0
  29. package/dist/context-integrity-analyzers.js.map +1 -0
  30. package/dist/context-integrity-contracts.d.ts +304 -0
  31. package/dist/context-integrity-contracts.d.ts.map +1 -0
  32. package/dist/context-integrity-contracts.js +24 -0
  33. package/dist/context-integrity-contracts.js.map +1 -0
  34. package/dist/context-integrity-model.d.ts +25 -0
  35. package/dist/context-integrity-model.d.ts.map +1 -0
  36. package/dist/context-integrity-model.js +192 -0
  37. package/dist/context-integrity-model.js.map +1 -0
  38. package/dist/context-integrity-portable-agent.d.ts +79 -0
  39. package/dist/context-integrity-portable-agent.d.ts.map +1 -0
  40. package/dist/context-integrity-portable-agent.js +511 -0
  41. package/dist/context-integrity-portable-agent.js.map +1 -0
  42. package/dist/context-integrity-role-alignment.d.ts +28 -0
  43. package/dist/context-integrity-role-alignment.d.ts.map +1 -0
  44. package/dist/context-integrity-role-alignment.js +95 -0
  45. package/dist/context-integrity-role-alignment.js.map +1 -0
  46. package/dist/context-integrity-runtime.d.ts +95 -0
  47. package/dist/context-integrity-runtime.d.ts.map +1 -0
  48. package/dist/context-integrity-runtime.js +1512 -0
  49. package/dist/context-integrity-runtime.js.map +1 -0
  50. package/dist/context-integrity.d.ts +5 -0
  51. package/dist/context-integrity.d.ts.map +1 -0
  52. package/dist/context-integrity.js +5 -0
  53. package/dist/context-integrity.js.map +1 -0
  54. package/dist/governed-role-evolution.d.ts +172 -0
  55. package/dist/governed-role-evolution.d.ts.map +1 -0
  56. package/dist/governed-role-evolution.js +613 -0
  57. package/dist/governed-role-evolution.js.map +1 -0
  58. package/dist/heterogeneous-agent-composition.d.ts +96 -0
  59. package/dist/heterogeneous-agent-composition.d.ts.map +1 -0
  60. package/dist/heterogeneous-agent-composition.js +512 -0
  61. package/dist/heterogeneous-agent-composition.js.map +1 -0
  62. package/dist/index.d.ts +21 -13
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +21 -13
  65. package/dist/index.js.map +1 -1
  66. package/dist/intervention-adapters.d.ts +29 -0
  67. package/dist/intervention-adapters.d.ts.map +1 -0
  68. package/dist/intervention-adapters.js +107 -0
  69. package/dist/intervention-adapters.js.map +1 -0
  70. package/dist/intervention-contracts.d.ts +311 -0
  71. package/dist/intervention-contracts.d.ts.map +1 -0
  72. package/dist/intervention-contracts.js +28 -0
  73. package/dist/intervention-contracts.js.map +1 -0
  74. package/dist/intervention-runtime.d.ts +86 -0
  75. package/dist/intervention-runtime.d.ts.map +1 -0
  76. package/dist/intervention-runtime.js +958 -0
  77. package/dist/intervention-runtime.js.map +1 -0
  78. package/dist/intervention-validation.d.ts +27 -0
  79. package/dist/intervention-validation.d.ts.map +1 -0
  80. package/dist/intervention-validation.js +273 -0
  81. package/dist/intervention-validation.js.map +1 -0
  82. package/dist/intervention.d.ts +6 -0
  83. package/dist/intervention.d.ts.map +1 -0
  84. package/dist/intervention.js +6 -0
  85. package/dist/intervention.js.map +1 -0
  86. package/dist/model.d.ts +18 -0
  87. package/dist/model.d.ts.map +1 -1
  88. package/dist/model.js +60 -2
  89. package/dist/model.js.map +1 -1
  90. package/dist/operational-cognitive-control.d.ts +208 -0
  91. package/dist/operational-cognitive-control.d.ts.map +1 -0
  92. package/dist/operational-cognitive-control.js +590 -0
  93. package/dist/operational-cognitive-control.js.map +1 -0
  94. package/dist/portable-agent.d.ts +50 -0
  95. package/dist/portable-agent.d.ts.map +1 -0
  96. package/dist/portable-agent.js +243 -0
  97. package/dist/portable-agent.js.map +1 -0
  98. package/dist/reference-controllers.d.ts +121 -0
  99. package/dist/reference-controllers.d.ts.map +1 -0
  100. package/dist/reference-controllers.js +411 -0
  101. package/dist/reference-controllers.js.map +1 -0
  102. package/dist/role-alignment-portable-agent.d.ts +145 -0
  103. package/dist/role-alignment-portable-agent.d.ts.map +1 -0
  104. package/dist/role-alignment-portable-agent.js +484 -0
  105. package/dist/role-alignment-portable-agent.js.map +1 -0
  106. package/dist/role-alignment.d.ts +226 -0
  107. package/dist/role-alignment.d.ts.map +1 -0
  108. package/dist/role-alignment.js +1074 -0
  109. package/dist/role-alignment.js.map +1 -0
  110. package/dist/role-realignment-portable-agent.d.ts +163 -0
  111. package/dist/role-realignment-portable-agent.d.ts.map +1 -0
  112. package/dist/role-realignment-portable-agent.js +634 -0
  113. package/dist/role-realignment-portable-agent.js.map +1 -0
  114. package/dist/role-realignment.d.ts +368 -0
  115. package/dist/role-realignment.d.ts.map +1 -0
  116. package/dist/role-realignment.js +1609 -0
  117. package/dist/role-realignment.js.map +1 -0
  118. package/dist/semantic-alignment-assessors.d.ts +12 -0
  119. package/dist/semantic-alignment-assessors.d.ts.map +1 -0
  120. package/dist/semantic-alignment-assessors.js +55 -0
  121. package/dist/semantic-alignment-assessors.js.map +1 -0
  122. package/dist/semantic-alignment-contracts.d.ts +385 -0
  123. package/dist/semantic-alignment-contracts.d.ts.map +1 -0
  124. package/dist/semantic-alignment-contracts.js +16 -0
  125. package/dist/semantic-alignment-contracts.js.map +1 -0
  126. package/dist/semantic-alignment-memory.d.ts +53 -0
  127. package/dist/semantic-alignment-memory.d.ts.map +1 -0
  128. package/dist/semantic-alignment-memory.js +170 -0
  129. package/dist/semantic-alignment-memory.js.map +1 -0
  130. package/dist/semantic-alignment-runtime.d.ts +67 -0
  131. package/dist/semantic-alignment-runtime.d.ts.map +1 -0
  132. package/dist/semantic-alignment-runtime.js +778 -0
  133. package/dist/semantic-alignment-runtime.js.map +1 -0
  134. package/dist/semantic-alignment-validation.d.ts +31 -0
  135. package/dist/semantic-alignment-validation.d.ts.map +1 -0
  136. package/dist/semantic-alignment-validation.js +477 -0
  137. package/dist/semantic-alignment-validation.js.map +1 -0
  138. package/dist/semantic-alignment.d.ts +8 -0
  139. package/dist/semantic-alignment.d.ts.map +1 -0
  140. package/dist/semantic-alignment.js +8 -0
  141. package/dist/semantic-alignment.js.map +1 -0
  142. package/dist/semantic-horizon-budget.d.ts +118 -0
  143. package/dist/semantic-horizon-budget.d.ts.map +1 -0
  144. package/dist/semantic-horizon-budget.js +536 -0
  145. package/dist/semantic-horizon-budget.js.map +1 -0
  146. package/dist/semantic-metric-engine.d.ts +96 -0
  147. package/dist/semantic-metric-engine.d.ts.map +1 -0
  148. package/dist/semantic-metric-engine.js +396 -0
  149. package/dist/semantic-metric-engine.js.map +1 -0
  150. package/package.json +79 -7
@@ -0,0 +1,1074 @@
1
+ import { canonicalizeControlJsonV1, utf8ByteLength } from './canonical.js';
2
+ import { sha256Hex } from './sha256.js';
3
+ import { assertDigest, assertExactKeys, assertIdentifier, assertOneOf, assertSafeInteger, assertStrictJsonValue, assertString, deepFreeze, sortedUnique, } from './validation.js';
4
+ export const ROLE_ALIGNMENT_SCHEMA_VERSION_V1 = 1;
5
+ export const ROLE_ALIGNMENT_BASIS_POINTS_V1 = 10_000;
6
+ const encoder = new TextEncoder();
7
+ const checkpoints = [
8
+ 'pre_step',
9
+ 'post_output',
10
+ 'pre_action',
11
+ ];
12
+ const interventions = [
13
+ 'continue',
14
+ 'reinforce_role',
15
+ 'challenge_context',
16
+ 'pause',
17
+ 'request_realign',
18
+ 'deny',
19
+ ];
20
+ const statuses = [
21
+ 'active',
22
+ 'paused',
23
+ 'realignment_required',
24
+ 'denied',
25
+ 'closed',
26
+ ];
27
+ export function digestRoleAlignmentJsonV1(domain, value) {
28
+ const canonical = canonicalizeControlJsonV1(value);
29
+ return `sha256:${sha256Hex(encoder.encode(`agentplat.inference-control/role-alignment/${domain}/v1\0${canonical}`))}`;
30
+ }
31
+ export function createRoleAlignmentPolicyRecordV1(input) {
32
+ const policy = validateRoleAlignmentPolicyV1(input);
33
+ return deepFreeze({
34
+ schemaVersion: 1,
35
+ policy,
36
+ policyDigest: digestRoleAlignmentJsonV1('policy', policy),
37
+ });
38
+ }
39
+ export function validateRoleAlignmentPolicyV1(input) {
40
+ assertExactKeys(input, [
41
+ 'schemaVersion',
42
+ 'policyId',
43
+ 'policyVersion',
44
+ 'parentPolicyDigest',
45
+ 'thresholds',
46
+ 'consecutiveBreachLimit',
47
+ 'recoverySignalsRequired',
48
+ 'reinforcementCooldownSignals',
49
+ 'denyActionsWhileDegraded',
50
+ 'budgets',
51
+ 'limits',
52
+ ], 'role alignment policy');
53
+ if (input.schemaVersion !== 1)
54
+ throw new TypeError('role_alignment_policy_invalid');
55
+ assertIdentifier(input.policyId, 'policyId');
56
+ assertSafeInteger(input.policyVersion, 'policyVersion', 1);
57
+ if (input.parentPolicyDigest !== null)
58
+ assertDigest(input.parentPolicyDigest, 'parentPolicyDigest');
59
+ if (typeof input.denyActionsWhileDegraded !== 'boolean')
60
+ throw new TypeError('role_alignment_policy_invalid');
61
+ assertSafeInteger(input.consecutiveBreachLimit, 'consecutiveBreachLimit', 1);
62
+ assertSafeInteger(input.recoverySignalsRequired, 'recoverySignalsRequired', 1);
63
+ assertSafeInteger(input.reinforcementCooldownSignals, 'reinforcementCooldownSignals');
64
+ validateThresholds(input.thresholds);
65
+ validateBudgets(input.budgets);
66
+ validateLimits(input.limits);
67
+ return cloneJson(input);
68
+ }
69
+ export function createRoleAlignmentRoleAnchorV1(input) {
70
+ for (const [label, value] of [
71
+ ['tenantId', input.tenantId],
72
+ ['sessionId', input.sessionId],
73
+ ['agentId', input.agentId],
74
+ ['objectiveId', input.objectiveId],
75
+ ['roleBindingId', input.roleBindingId],
76
+ ])
77
+ assertIdentifier(value, label);
78
+ assertSafeInteger(input.roleRevision, 'roleRevision', 1);
79
+ if (input.predecessorRoleBindingId !== null)
80
+ assertIdentifier(input.predecessorRoleBindingId, 'predecessorRoleBindingId');
81
+ assertString(input.roleKey, 'roleKey');
82
+ assertStrictJsonValue(input.roleContent);
83
+ const roleContentDigest = digestRoleAlignmentJsonV1('role_anchor', input.roleContent);
84
+ const withoutDigest = {
85
+ schemaVersion: 1,
86
+ tenantId: input.tenantId,
87
+ sessionId: input.sessionId,
88
+ agentId: input.agentId,
89
+ objectiveId: input.objectiveId,
90
+ roleBindingId: input.roleBindingId,
91
+ roleRevision: input.roleRevision,
92
+ predecessorRoleBindingId: input.predecessorRoleBindingId,
93
+ roleKey: input.roleKey,
94
+ roleContentDigest,
95
+ };
96
+ return deepFreeze({
97
+ ...withoutDigest,
98
+ anchorDigest: digestRoleAlignmentJsonV1('role_anchor', withoutDigest),
99
+ });
100
+ }
101
+ export function validateRoleAlignmentRoleAnchorV1(input) {
102
+ assertExactKeys(input, [
103
+ 'schemaVersion',
104
+ 'tenantId',
105
+ 'sessionId',
106
+ 'agentId',
107
+ 'objectiveId',
108
+ 'roleBindingId',
109
+ 'roleRevision',
110
+ 'predecessorRoleBindingId',
111
+ 'roleKey',
112
+ 'roleContentDigest',
113
+ 'anchorDigest',
114
+ ], 'role alignment anchor');
115
+ if (input.schemaVersion !== 1)
116
+ throw new TypeError('role_alignment_anchor_invalid');
117
+ for (const [label, value] of [
118
+ ['tenantId', input.tenantId],
119
+ ['sessionId', input.sessionId],
120
+ ['agentId', input.agentId],
121
+ ['objectiveId', input.objectiveId],
122
+ ['roleBindingId', input.roleBindingId],
123
+ ])
124
+ assertIdentifier(value, label);
125
+ assertSafeInteger(input.roleRevision, 'roleRevision', 1);
126
+ if (input.predecessorRoleBindingId !== null)
127
+ assertIdentifier(input.predecessorRoleBindingId, 'predecessorRoleBindingId');
128
+ assertString(input.roleKey, 'roleKey');
129
+ assertDigest(input.roleContentDigest, 'roleContentDigest');
130
+ assertDigest(input.anchorDigest, 'anchorDigest');
131
+ const { anchorDigest: _ignored, ...withoutDigest } = input;
132
+ if (digestRoleAlignmentJsonV1('role_anchor', withoutDigest) !== input.anchorDigest)
133
+ throw new TypeError('role_alignment_anchor_invalid');
134
+ return cloneJson(input);
135
+ }
136
+ export function createRoleAlignmentStateV1(input) {
137
+ assertIdentifier(input.controllerId, 'controllerId');
138
+ assertSafeInteger(input.controllerVersion, 'controllerVersion', 1);
139
+ assertIdentifier(input.implementationId, 'implementationId');
140
+ assertSafeInteger(input.createdAtLogicalMs, 'createdAtLogicalMs');
141
+ const policyRecord = createRoleAlignmentPolicyRecordV1(input.policy);
142
+ const roleAnchor = validateRoleAlignmentRoleAnchorV1(input.roleAnchor);
143
+ const state = withStateDigest({
144
+ schemaVersion: 1,
145
+ controllerId: input.controllerId,
146
+ controllerVersion: input.controllerVersion,
147
+ implementationId: input.implementationId,
148
+ policyId: policyRecord.policy.policyId,
149
+ policyVersion: policyRecord.policy.policyVersion,
150
+ policyDigest: policyRecord.policyDigest,
151
+ tenantId: roleAnchor.tenantId,
152
+ sessionId: roleAnchor.sessionId,
153
+ agentId: roleAnchor.agentId,
154
+ objectiveId: roleAnchor.objectiveId,
155
+ roleAnchor,
156
+ status: 'active',
157
+ revision: 0,
158
+ signalCount: 0,
159
+ degraded: false,
160
+ consecutiveBreaches: 0,
161
+ recoveryStreak: 0,
162
+ interventionCounts: {
163
+ reinforcements: 0,
164
+ contextChallenges: 0,
165
+ pauses: 0,
166
+ },
167
+ lastInterventionEventSequence: null,
168
+ rollingWindow: [],
169
+ rollingCoherenceBps: null,
170
+ lastLogicalTimeMs: input.createdAtLogicalMs,
171
+ lastEventDigest: null,
172
+ events: [],
173
+ });
174
+ ensureStateCapacity(state, policyRecord.policy);
175
+ return state;
176
+ }
177
+ export function observeRoleAlignmentSignalV1(stateInput, input, policyInput) {
178
+ const policy = assertRoleAlignmentStateV1(stateInput, policyInput);
179
+ const state = stateInput;
180
+ requireExpectedRevision(state, input.expectedRevision);
181
+ if (state.status !== 'active')
182
+ throw new TypeError(`role_alignment_${state.status}`);
183
+ const signal = validateSignal(input.signal, state, policy);
184
+ if (state.signalCount >= policy.limits.maximumSignals)
185
+ throw new TypeError('role_alignment_capacity_exhausted');
186
+ const windowEntry = deepFreeze({
187
+ schemaVersion: 1,
188
+ signalId: signal.signalId,
189
+ stepId: signal.stepId,
190
+ checkpoint: signal.checkpoint,
191
+ coherenceBps: signal.coherenceBps,
192
+ uncertaintyBps: signal.uncertaintyBps,
193
+ contextInconsistencyBps: signal.contextInconsistencyBps,
194
+ hardViolation: signal.hardViolation,
195
+ observedAtLogicalMs: signal.observedAtLogicalMs,
196
+ });
197
+ const rollingWindow = [...state.rollingWindow, windowEntry].slice(-policy.limits.rollingWindowSignals);
198
+ const rollingCoherenceBps = average(rollingWindow.map(({ coherenceBps }) => coherenceBps));
199
+ const healthyNow = isHealthy(signal, policy);
200
+ const consecutiveBreaches = healthyNow ? 0 : state.consecutiveBreaches + 1;
201
+ const recoveryStreak = healthyNow
202
+ ? state.degraded
203
+ ? state.recoveryStreak + 1
204
+ : 0
205
+ : 0;
206
+ const degraded = healthyNow
207
+ ? state.degraded && recoveryStreak < policy.recoverySignalsRequired
208
+ : true;
209
+ const effectiveCoherenceBps = Math.min(signal.coherenceBps, rollingCoherenceBps);
210
+ const provisional = chooseIntervention({
211
+ state,
212
+ signal,
213
+ policy,
214
+ degraded,
215
+ consecutiveBreaches,
216
+ effectiveCoherenceBps,
217
+ });
218
+ const decision = makeDecision(provisional.intervention, provisional.reasonCode, effectiveCoherenceBps, degraded);
219
+ const event = createEvent({
220
+ state,
221
+ eventType: 'signal_evaluated',
222
+ inputDigest: signal.targetDigest,
223
+ roleAnchorDigest: state.roleAnchor.anchorDigest,
224
+ signal,
225
+ decision,
226
+ reasonCode: decision.reasonCode,
227
+ logicalTimeMs: signal.observedAtLogicalMs,
228
+ });
229
+ const interventionCounts = countIntervention(state.interventionCounts, decision.intervention);
230
+ const nextState = withStateDigest({
231
+ ...withoutStateDigest(state),
232
+ status: decision.stateStatus,
233
+ revision: state.revision + 1,
234
+ signalCount: state.signalCount + 1,
235
+ degraded,
236
+ consecutiveBreaches,
237
+ recoveryStreak,
238
+ interventionCounts,
239
+ lastInterventionEventSequence: decision.intervention === 'continue'
240
+ ? state.lastInterventionEventSequence
241
+ : event.eventSequence,
242
+ rollingWindow,
243
+ rollingCoherenceBps,
244
+ lastLogicalTimeMs: signal.observedAtLogicalMs,
245
+ lastEventDigest: event.eventDigest,
246
+ events: retainEvents(state.events, event, policy),
247
+ });
248
+ ensureStateCapacity(nextState, policy);
249
+ return deepFreeze({ state: nextState, decision, event });
250
+ }
251
+ export function replaceRoleAlignmentRoleV1(stateInput, input, policyInput) {
252
+ const policy = assertRoleAlignmentStateV1(stateInput, policyInput);
253
+ const state = stateInput;
254
+ requireExpectedRevision(state, input.expectedRevision);
255
+ if (state.status === 'closed')
256
+ throw new TypeError('role_alignment_closed');
257
+ assertSafeInteger(input.logicalTimeMs, 'logicalTimeMs');
258
+ if (input.logicalTimeMs < state.lastLogicalTimeMs)
259
+ throw new TypeError('role_alignment_clock_rollback');
260
+ const anchor = validateRoleAlignmentRoleAnchorV1(input.roleAnchor);
261
+ if (anchor.tenantId !== state.tenantId ||
262
+ anchor.sessionId !== state.sessionId ||
263
+ anchor.agentId !== state.agentId ||
264
+ anchor.objectiveId !== state.objectiveId ||
265
+ anchor.roleRevision !== state.roleAnchor.roleRevision + 1 ||
266
+ anchor.predecessorRoleBindingId !== state.roleAnchor.roleBindingId ||
267
+ anchor.anchorDigest === state.roleAnchor.anchorDigest)
268
+ throw new TypeError('role_alignment_role_transition_invalid');
269
+ const event = createEvent({
270
+ state,
271
+ eventType: 'role_replaced',
272
+ inputDigest: anchor.anchorDigest,
273
+ roleAnchorDigest: anchor.anchorDigest,
274
+ signal: null,
275
+ decision: null,
276
+ reasonCode: 'role_replaced',
277
+ logicalTimeMs: input.logicalTimeMs,
278
+ });
279
+ const next = withStateDigest({
280
+ ...withoutStateDigest(state),
281
+ roleAnchor: anchor,
282
+ status: 'active',
283
+ revision: state.revision + 1,
284
+ degraded: false,
285
+ consecutiveBreaches: 0,
286
+ recoveryStreak: 0,
287
+ interventionCounts: {
288
+ reinforcements: 0,
289
+ contextChallenges: 0,
290
+ pauses: 0,
291
+ },
292
+ lastInterventionEventSequence: null,
293
+ rollingWindow: [],
294
+ rollingCoherenceBps: null,
295
+ lastLogicalTimeMs: input.logicalTimeMs,
296
+ lastEventDigest: event.eventDigest,
297
+ events: retainEvents(state.events, event, policy),
298
+ });
299
+ ensureStateCapacity(next, policy);
300
+ return next;
301
+ }
302
+ export function resumeRoleAlignmentStateV1(stateInput, input, policyInput) {
303
+ const policy = assertRoleAlignmentStateV1(stateInput, policyInput);
304
+ const state = stateInput;
305
+ requireExpectedRevision(state, input.expectedRevision);
306
+ if (state.status !== 'paused')
307
+ throw new TypeError('role_alignment_not_paused');
308
+ assertSafeInteger(input.logicalTimeMs, 'logicalTimeMs');
309
+ assertIdentifier(input.reasonCode, 'reasonCode');
310
+ if (input.logicalTimeMs < state.lastLogicalTimeMs)
311
+ throw new TypeError('role_alignment_clock_rollback');
312
+ const event = createEvent({
313
+ state,
314
+ eventType: 'resumed',
315
+ inputDigest: digestRoleAlignmentJsonV1('event', {
316
+ expectedRevision: input.expectedRevision,
317
+ reasonCode: input.reasonCode,
318
+ }),
319
+ roleAnchorDigest: state.roleAnchor.anchorDigest,
320
+ signal: null,
321
+ decision: null,
322
+ reasonCode: input.reasonCode,
323
+ logicalTimeMs: input.logicalTimeMs,
324
+ });
325
+ const next = withStateDigest({
326
+ ...withoutStateDigest(state),
327
+ status: 'active',
328
+ revision: state.revision + 1,
329
+ lastLogicalTimeMs: input.logicalTimeMs,
330
+ lastEventDigest: event.eventDigest,
331
+ events: retainEvents(state.events, event, policy),
332
+ });
333
+ ensureStateCapacity(next, policy);
334
+ return next;
335
+ }
336
+ export function closeRoleAlignmentStateV1(stateInput, input, policyInput) {
337
+ const policy = assertRoleAlignmentStateV1(stateInput, policyInput);
338
+ const state = stateInput;
339
+ requireExpectedRevision(state, input.expectedRevision);
340
+ if (state.status === 'closed')
341
+ return state;
342
+ assertSafeInteger(input.logicalTimeMs, 'logicalTimeMs');
343
+ assertIdentifier(input.reasonCode, 'reasonCode');
344
+ if (input.logicalTimeMs < state.lastLogicalTimeMs)
345
+ throw new TypeError('role_alignment_clock_rollback');
346
+ const event = createEvent({
347
+ state,
348
+ eventType: 'closed',
349
+ inputDigest: digestRoleAlignmentJsonV1('event', {
350
+ reasonCode: input.reasonCode,
351
+ }),
352
+ roleAnchorDigest: state.roleAnchor.anchorDigest,
353
+ signal: null,
354
+ decision: null,
355
+ reasonCode: input.reasonCode,
356
+ logicalTimeMs: input.logicalTimeMs,
357
+ });
358
+ const next = withStateDigest({
359
+ ...withoutStateDigest(state),
360
+ status: 'closed',
361
+ revision: state.revision + 1,
362
+ lastLogicalTimeMs: input.logicalTimeMs,
363
+ lastEventDigest: event.eventDigest,
364
+ events: retainEvents(state.events, event, policy),
365
+ });
366
+ ensureStateCapacity(next, policy);
367
+ return next;
368
+ }
369
+ /**
370
+ * Rebinds a verified source state to a new portable session while preserving
371
+ * its causal record and rolling coherence window.
372
+ */
373
+ export function rebindRoleAlignmentSessionV1(stateInput, input, policyInput) {
374
+ const policy = assertRoleAlignmentStateV1(stateInput, policyInput);
375
+ const state = stateInput;
376
+ requireExpectedRevision(state, input.expectedRevision);
377
+ if (state.status === 'closed')
378
+ throw new TypeError('role_alignment_closed');
379
+ assertSafeInteger(input.logicalTimeMs, 'logicalTimeMs');
380
+ assertDigest(input.transferDigest, 'transferDigest');
381
+ if (input.logicalTimeMs < state.lastLogicalTimeMs)
382
+ throw new TypeError('role_alignment_clock_rollback');
383
+ const anchor = validateRoleAlignmentRoleAnchorV1(input.targetRoleAnchor);
384
+ if (anchor.tenantId !== state.tenantId ||
385
+ anchor.objectiveId !== state.objectiveId ||
386
+ anchor.sessionId === state.sessionId)
387
+ throw new TypeError('role_alignment_handoff_invalid');
388
+ const reboundBase = {
389
+ ...state,
390
+ sessionId: anchor.sessionId,
391
+ agentId: anchor.agentId,
392
+ roleAnchor: anchor,
393
+ };
394
+ const event = createEvent({
395
+ state: reboundBase,
396
+ eventType: 'session_handoff',
397
+ inputDigest: input.transferDigest,
398
+ roleAnchorDigest: anchor.anchorDigest,
399
+ signal: null,
400
+ decision: null,
401
+ reasonCode: 'session_handoff_imported',
402
+ logicalTimeMs: input.logicalTimeMs,
403
+ });
404
+ const next = withStateDigest({
405
+ ...withoutStateDigest(reboundBase),
406
+ revision: state.revision + 1,
407
+ lastLogicalTimeMs: input.logicalTimeMs,
408
+ lastEventDigest: event.eventDigest,
409
+ events: retainEvents(state.events, event, policy),
410
+ });
411
+ ensureStateCapacity(next, policy);
412
+ return next;
413
+ }
414
+ export function assertRoleAlignmentStateV1(input, policyInput, binding = {}) {
415
+ const policyRecord = createRoleAlignmentPolicyRecordV1(policyInput);
416
+ assertExactKeys(input, [
417
+ 'schemaVersion',
418
+ 'controllerId',
419
+ 'controllerVersion',
420
+ 'implementationId',
421
+ 'policyId',
422
+ 'policyVersion',
423
+ 'policyDigest',
424
+ 'tenantId',
425
+ 'sessionId',
426
+ 'agentId',
427
+ 'objectiveId',
428
+ 'roleAnchor',
429
+ 'status',
430
+ 'revision',
431
+ 'signalCount',
432
+ 'degraded',
433
+ 'consecutiveBreaches',
434
+ 'recoveryStreak',
435
+ 'interventionCounts',
436
+ 'lastInterventionEventSequence',
437
+ 'rollingWindow',
438
+ 'rollingCoherenceBps',
439
+ 'lastLogicalTimeMs',
440
+ 'lastEventDigest',
441
+ 'events',
442
+ 'stateDigest',
443
+ ], 'role alignment state');
444
+ if (input.schemaVersion !== 1)
445
+ throw new TypeError('role_alignment_state_invalid');
446
+ for (const [label, value] of [
447
+ ['controllerId', input.controllerId],
448
+ ['implementationId', input.implementationId],
449
+ ['policyId', input.policyId],
450
+ ['tenantId', input.tenantId],
451
+ ['sessionId', input.sessionId],
452
+ ['agentId', input.agentId],
453
+ ['objectiveId', input.objectiveId],
454
+ ])
455
+ assertIdentifier(value, label);
456
+ assertSafeInteger(input.controllerVersion, 'controllerVersion', 1);
457
+ assertSafeInteger(input.policyVersion, 'policyVersion', 1);
458
+ assertDigest(input.policyDigest, 'policyDigest');
459
+ assertDigest(input.stateDigest, 'stateDigest');
460
+ assertOneOf(input.status, statuses, 'status');
461
+ for (const [label, value] of [
462
+ ['revision', input.revision],
463
+ ['signalCount', input.signalCount],
464
+ ['consecutiveBreaches', input.consecutiveBreaches],
465
+ ['recoveryStreak', input.recoveryStreak],
466
+ ['lastLogicalTimeMs', input.lastLogicalTimeMs],
467
+ ])
468
+ assertSafeInteger(value, label);
469
+ if (typeof input.degraded !== 'boolean')
470
+ throw new TypeError('role_alignment_state_invalid');
471
+ if (input.policyId !== policyRecord.policy.policyId ||
472
+ input.policyVersion !== policyRecord.policy.policyVersion ||
473
+ input.policyDigest !== policyRecord.policyDigest ||
474
+ (binding.controllerId !== undefined &&
475
+ input.controllerId !== binding.controllerId) ||
476
+ (binding.controllerVersion !== undefined &&
477
+ input.controllerVersion !== binding.controllerVersion) ||
478
+ (binding.implementationId !== undefined &&
479
+ input.implementationId !== binding.implementationId) ||
480
+ (binding.sessionId !== undefined && input.sessionId !== binding.sessionId))
481
+ throw new TypeError('role_alignment_state_binding_mismatch');
482
+ const anchor = validateRoleAlignmentRoleAnchorV1(input.roleAnchor);
483
+ if (anchor.tenantId !== input.tenantId ||
484
+ anchor.sessionId !== input.sessionId ||
485
+ anchor.agentId !== input.agentId ||
486
+ anchor.objectiveId !== input.objectiveId)
487
+ throw new TypeError('role_alignment_state_binding_mismatch');
488
+ validateInterventionCounts(input.interventionCounts);
489
+ if (input.lastInterventionEventSequence !== null)
490
+ assertSafeInteger(input.lastInterventionEventSequence, 'lastInterventionEventSequence', 1);
491
+ if (!Array.isArray(input.rollingWindow) || !Array.isArray(input.events))
492
+ throw new TypeError('role_alignment_state_invalid');
493
+ if (input.rollingWindow.length >
494
+ policyRecord.policy.limits.rollingWindowSignals ||
495
+ input.signalCount > policyRecord.policy.limits.maximumSignals ||
496
+ input.events.length > policyRecord.policy.limits.maximumRetainedEvents)
497
+ throw new TypeError('role_alignment_capacity_exhausted');
498
+ if (input.revision < input.events.length ||
499
+ (input.revision === 0) !== (input.events.length === 0) ||
500
+ (input.lastInterventionEventSequence !== null &&
501
+ input.lastInterventionEventSequence > input.revision))
502
+ throw new TypeError('role_alignment_state_invalid');
503
+ for (const entry of input.rollingWindow)
504
+ validateWindowEntry(entry);
505
+ const firstRetainedEventSequence = input.revision - input.events.length + 1;
506
+ const completeHistory = firstRetainedEventSequence === 1;
507
+ let previousEventDigest = completeHistory
508
+ ? null
509
+ : (input.events[0]?.previousEventDigest ?? null);
510
+ if (!completeHistory && previousEventDigest === null)
511
+ throw new TypeError('role_alignment_event_chain_invalid');
512
+ let previousLogicalTimeMs = -1;
513
+ let signals = 0;
514
+ let replayStatus = 'active';
515
+ let replayDegraded = false;
516
+ let replayConsecutiveBreaches = 0;
517
+ let replayRecoveryStreak = 0;
518
+ let replayCounts = {
519
+ reinforcements: 0,
520
+ contextChallenges: 0,
521
+ pauses: 0,
522
+ };
523
+ let replayLastIntervention = null;
524
+ let replayWindow = [];
525
+ let replayAnchorDigest = null;
526
+ for (let index = 0; index < input.events.length; index += 1) {
527
+ const event = validateEvent(input.events[index], policyRecord.policy);
528
+ if (event.eventSequence !== firstRetainedEventSequence + index ||
529
+ event.previousEventDigest !== previousEventDigest ||
530
+ event.logicalTimeMs < previousLogicalTimeMs)
531
+ throw new TypeError('role_alignment_event_chain_invalid');
532
+ previousEventDigest = event.eventDigest;
533
+ previousLogicalTimeMs = event.logicalTimeMs;
534
+ if (event.signal !== null)
535
+ signals += 1;
536
+ if (!completeHistory)
537
+ continue;
538
+ if (event.eventType === 'signal_evaluated') {
539
+ if (replayStatus !== 'active' ||
540
+ event.signal === null ||
541
+ event.decision === null)
542
+ throw new TypeError('role_alignment_event_chain_invalid');
543
+ if (replayAnchorDigest !== null &&
544
+ event.roleAnchorDigest !== replayAnchorDigest)
545
+ throw new TypeError('role_alignment_event_chain_invalid');
546
+ replayAnchorDigest = event.roleAnchorDigest;
547
+ const windowEntry = {
548
+ schemaVersion: 1,
549
+ signalId: event.signal.signalId,
550
+ stepId: event.signal.stepId,
551
+ checkpoint: event.signal.checkpoint,
552
+ coherenceBps: event.signal.coherenceBps,
553
+ uncertaintyBps: event.signal.uncertaintyBps,
554
+ contextInconsistencyBps: event.signal.contextInconsistencyBps,
555
+ hardViolation: event.signal.hardViolation,
556
+ observedAtLogicalMs: event.signal.observedAtLogicalMs,
557
+ };
558
+ replayWindow = [...replayWindow, windowEntry].slice(-policyRecord.policy.limits.rollingWindowSignals);
559
+ const healthyNow = isHealthy(event.signal, policyRecord.policy);
560
+ replayConsecutiveBreaches = healthyNow
561
+ ? 0
562
+ : replayConsecutiveBreaches + 1;
563
+ replayRecoveryStreak = healthyNow
564
+ ? replayDegraded
565
+ ? replayRecoveryStreak + 1
566
+ : 0
567
+ : 0;
568
+ replayDegraded = healthyNow
569
+ ? replayDegraded &&
570
+ replayRecoveryStreak < policyRecord.policy.recoverySignalsRequired
571
+ : true;
572
+ const effectiveCoherenceBps = Math.min(event.signal.coherenceBps, average(replayWindow.map(({ coherenceBps }) => coherenceBps)));
573
+ const replayState = {
574
+ ...input,
575
+ revision: event.eventSequence - 1,
576
+ status: replayStatus,
577
+ degraded: replayDegraded,
578
+ consecutiveBreaches: replayConsecutiveBreaches,
579
+ recoveryStreak: replayRecoveryStreak,
580
+ interventionCounts: replayCounts,
581
+ lastInterventionEventSequence: replayLastIntervention,
582
+ events: input.events.slice(0, index),
583
+ };
584
+ const expectedIntervention = chooseIntervention({
585
+ state: replayState,
586
+ signal: event.signal,
587
+ policy: policyRecord.policy,
588
+ degraded: replayDegraded,
589
+ consecutiveBreaches: replayConsecutiveBreaches,
590
+ effectiveCoherenceBps,
591
+ });
592
+ const expectedDecision = makeDecision(expectedIntervention.intervention, expectedIntervention.reasonCode, effectiveCoherenceBps, replayDegraded);
593
+ if (canonicalizeControlJsonV1(event.decision) !==
594
+ canonicalizeControlJsonV1(expectedDecision))
595
+ throw new TypeError('role_alignment_decision_invalid');
596
+ replayStatus = event.decision.stateStatus;
597
+ replayCounts = countIntervention(replayCounts, event.decision.intervention);
598
+ if (event.decision.intervention !== 'continue')
599
+ replayLastIntervention = event.eventSequence;
600
+ }
601
+ else if (event.eventType === 'role_replaced') {
602
+ if (replayStatus === 'closed' ||
603
+ (replayAnchorDigest !== null &&
604
+ event.roleAnchorDigest === replayAnchorDigest))
605
+ throw new TypeError('role_alignment_event_chain_invalid');
606
+ replayAnchorDigest = event.roleAnchorDigest;
607
+ replayStatus = 'active';
608
+ replayDegraded = false;
609
+ replayConsecutiveBreaches = 0;
610
+ replayRecoveryStreak = 0;
611
+ replayCounts = {
612
+ reinforcements: 0,
613
+ contextChallenges: 0,
614
+ pauses: 0,
615
+ };
616
+ replayLastIntervention = null;
617
+ replayWindow = [];
618
+ }
619
+ else if (event.eventType === 'resumed') {
620
+ if (replayStatus !== 'paused')
621
+ throw new TypeError('role_alignment_event_chain_invalid');
622
+ replayStatus = 'active';
623
+ }
624
+ else if (event.eventType === 'closed') {
625
+ if (replayStatus === 'closed')
626
+ throw new TypeError('role_alignment_event_chain_invalid');
627
+ replayStatus = 'closed';
628
+ }
629
+ else {
630
+ if (replayStatus === 'closed')
631
+ throw new TypeError('role_alignment_event_chain_invalid');
632
+ replayAnchorDigest = event.roleAnchorDigest;
633
+ }
634
+ }
635
+ const expectedRolling = replayWindow.length
636
+ ? average(replayWindow.map(({ coherenceBps }) => coherenceBps))
637
+ : null;
638
+ if (input.lastEventDigest !== previousEventDigest ||
639
+ signals > input.signalCount ||
640
+ (input.events.length > 0 &&
641
+ (input.lastLogicalTimeMs !==
642
+ input.events[input.events.length - 1].logicalTimeMs ||
643
+ input.roleAnchor.anchorDigest !==
644
+ input.events[input.events.length - 1].roleAnchorDigest)))
645
+ throw new TypeError('role_alignment_state_invalid');
646
+ if (completeHistory &&
647
+ (signals !== input.signalCount ||
648
+ input.status !== replayStatus ||
649
+ input.degraded !== replayDegraded ||
650
+ input.consecutiveBreaches !== replayConsecutiveBreaches ||
651
+ input.recoveryStreak !== replayRecoveryStreak ||
652
+ input.interventionCounts.reinforcements !== replayCounts.reinforcements ||
653
+ input.interventionCounts.contextChallenges !==
654
+ replayCounts.contextChallenges ||
655
+ input.interventionCounts.pauses !== replayCounts.pauses ||
656
+ input.lastInterventionEventSequence !== replayLastIntervention ||
657
+ input.rollingCoherenceBps !== expectedRolling ||
658
+ canonicalizeControlJsonV1(input.rollingWindow) !==
659
+ canonicalizeControlJsonV1(replayWindow) ||
660
+ (replayAnchorDigest !== null &&
661
+ input.roleAnchor.anchorDigest !== replayAnchorDigest)))
662
+ throw new TypeError('role_alignment_state_invalid');
663
+ const expectedStateDigest = digestRoleAlignmentJsonV1('state', withoutStateDigest(input));
664
+ if (expectedStateDigest !== input.stateDigest)
665
+ throw new TypeError('role_alignment_state_digest_mismatch');
666
+ ensureStateCapacity(input, policyRecord.policy);
667
+ return policyRecord.policy;
668
+ }
669
+ export function findRoleAlignmentDecisionV1(state, inputDigest) {
670
+ assertDigest(inputDigest, 'inputDigest');
671
+ for (let index = state.events.length - 1; index >= 0; index -= 1) {
672
+ const event = state.events[index];
673
+ if (event.inputDigest === inputDigest && event.decision !== null)
674
+ return event.decision;
675
+ }
676
+ return undefined;
677
+ }
678
+ export function decisionForInactiveRoleAlignmentStateV1(state) {
679
+ switch (state.status) {
680
+ case 'paused':
681
+ return makeDecision('pause', 'alignment_paused', state.rollingCoherenceBps ?? 0, state.degraded);
682
+ case 'realignment_required':
683
+ return makeDecision('request_realign', 'role_realignment_required', state.rollingCoherenceBps ?? 0, state.degraded);
684
+ case 'denied':
685
+ case 'closed':
686
+ return makeDecision('deny', state.status === 'closed' ? 'alignment_closed' : 'alignment_denied', state.rollingCoherenceBps ?? 0, state.degraded);
687
+ case 'active':
688
+ throw new TypeError('role_alignment_state_is_active');
689
+ }
690
+ }
691
+ function validateThresholds(input) {
692
+ assertExactKeys(input, [
693
+ 'healthyCoherenceBps',
694
+ 'reinforceCoherenceBelowBps',
695
+ 'pauseCoherenceAtOrBelowBps',
696
+ 'denyCoherenceAtOrBelowBps',
697
+ 'challengeContextAtOrAboveBps',
698
+ 'maximumUncertaintyBps',
699
+ ], 'role alignment thresholds');
700
+ for (const [label, value] of Object.entries(input))
701
+ basisPoints(value, label);
702
+ if (input.denyCoherenceAtOrBelowBps > input.pauseCoherenceAtOrBelowBps ||
703
+ input.pauseCoherenceAtOrBelowBps >= input.reinforceCoherenceBelowBps ||
704
+ input.reinforceCoherenceBelowBps > input.healthyCoherenceBps)
705
+ throw new TypeError('role_alignment_threshold_order_invalid');
706
+ }
707
+ function validateBudgets(input) {
708
+ assertExactKeys(input, ['maximumReinforcements', 'maximumContextChallenges', 'maximumPauses'], 'role alignment budgets');
709
+ assertSafeInteger(input.maximumReinforcements, 'maximumReinforcements', 1);
710
+ assertSafeInteger(input.maximumContextChallenges, 'maximumContextChallenges', 1);
711
+ assertSafeInteger(input.maximumPauses, 'maximumPauses', 1);
712
+ }
713
+ function validateLimits(input) {
714
+ assertExactKeys(input, [
715
+ 'rollingWindowSignals',
716
+ 'maximumSignals',
717
+ 'maximumRetainedEvents',
718
+ 'maximumReasonCodesPerSignal',
719
+ 'maximumEvidenceReferencesPerSignal',
720
+ 'maximumAssessmentTtlMs',
721
+ 'maximumStateBytes',
722
+ ], 'role alignment limits');
723
+ assertSafeInteger(input.rollingWindowSignals, 'rollingWindowSignals', 1);
724
+ assertSafeInteger(input.maximumSignals, 'maximumSignals', 1);
725
+ assertSafeInteger(input.maximumRetainedEvents, 'maximumRetainedEvents', 1);
726
+ assertSafeInteger(input.maximumReasonCodesPerSignal, 'maximumReasonCodesPerSignal', 1);
727
+ assertSafeInteger(input.maximumEvidenceReferencesPerSignal, 'maximumEvidenceReferencesPerSignal', 1);
728
+ assertSafeInteger(input.maximumAssessmentTtlMs, 'maximumAssessmentTtlMs', 1);
729
+ assertSafeInteger(input.maximumStateBytes, 'maximumStateBytes', 1_024);
730
+ if (input.rollingWindowSignals > 4_096 ||
731
+ input.maximumSignals > 1_000_000 ||
732
+ input.maximumRetainedEvents > 4_096 ||
733
+ input.maximumRetainedEvents < input.rollingWindowSignals ||
734
+ input.rollingWindowSignals > input.maximumSignals ||
735
+ input.maximumReasonCodesPerSignal > 64 ||
736
+ input.maximumEvidenceReferencesPerSignal > 256 ||
737
+ input.maximumAssessmentTtlMs > 3_600_000 ||
738
+ input.maximumStateBytes > 67_108_864)
739
+ throw new TypeError('role_alignment_limit_invalid');
740
+ }
741
+ function validateSignal(input, state, policy) {
742
+ validateSignalShape(input, policy);
743
+ if (input.tenantId !== state.tenantId ||
744
+ input.sessionId !== state.sessionId ||
745
+ input.agentId !== state.agentId ||
746
+ input.roleAnchorDigest !== state.roleAnchor.anchorDigest ||
747
+ input.roleRevision !== state.roleAnchor.roleRevision ||
748
+ input.observedAtLogicalMs < state.lastLogicalTimeMs)
749
+ throw new TypeError('role_alignment_signal_binding_invalid');
750
+ return cloneJson(input);
751
+ }
752
+ function validateSignalShape(input, policy) {
753
+ assertExactKeys(input, [
754
+ 'schemaVersion',
755
+ 'signalId',
756
+ 'assessmentRequestId',
757
+ 'assessorId',
758
+ 'assessorVersion',
759
+ 'assessorBindingDigest',
760
+ 'tenantId',
761
+ 'sessionId',
762
+ 'agentId',
763
+ 'stepId',
764
+ 'checkpoint',
765
+ 'roleAnchorDigest',
766
+ 'roleRevision',
767
+ 'targetDigest',
768
+ 'coherenceBps',
769
+ 'uncertaintyBps',
770
+ 'contextInconsistencyBps',
771
+ 'hardViolation',
772
+ 'reasonCodes',
773
+ 'evidenceReferenceIds',
774
+ 'observedAtLogicalMs',
775
+ 'expiresAtLogicalMs',
776
+ ], 'role alignment signal');
777
+ if (input.schemaVersion !== 1)
778
+ throw new TypeError('role_alignment_signal_invalid');
779
+ for (const [label, value] of [
780
+ ['signalId', input.signalId],
781
+ ['assessmentRequestId', input.assessmentRequestId],
782
+ ['assessorId', input.assessorId],
783
+ ['tenantId', input.tenantId],
784
+ ['sessionId', input.sessionId],
785
+ ['agentId', input.agentId],
786
+ ['stepId', input.stepId],
787
+ ])
788
+ assertIdentifier(value, label);
789
+ assertSafeInteger(input.assessorVersion, 'assessorVersion', 1);
790
+ assertDigest(input.assessorBindingDigest, 'assessorBindingDigest');
791
+ assertOneOf(input.checkpoint, checkpoints, 'checkpoint');
792
+ assertDigest(input.roleAnchorDigest, 'roleAnchorDigest');
793
+ assertSafeInteger(input.roleRevision, 'roleRevision', 1);
794
+ assertDigest(input.targetDigest, 'targetDigest');
795
+ basisPoints(input.coherenceBps, 'coherenceBps');
796
+ basisPoints(input.uncertaintyBps, 'uncertaintyBps');
797
+ basisPoints(input.contextInconsistencyBps, 'contextInconsistencyBps');
798
+ if (typeof input.hardViolation !== 'boolean')
799
+ throw new TypeError('role_alignment_signal_invalid');
800
+ validateStringArray(input.reasonCodes, policy.limits.maximumReasonCodesPerSignal, 'reasonCodes');
801
+ validateStringArray(input.evidenceReferenceIds, policy.limits.maximumEvidenceReferencesPerSignal, 'evidenceReferenceIds');
802
+ assertSafeInteger(input.observedAtLogicalMs, 'observedAtLogicalMs');
803
+ assertSafeInteger(input.expiresAtLogicalMs, 'expiresAtLogicalMs');
804
+ if (input.expiresAtLogicalMs <= input.observedAtLogicalMs ||
805
+ input.expiresAtLogicalMs - input.observedAtLogicalMs >
806
+ policy.limits.maximumAssessmentTtlMs)
807
+ throw new TypeError('role_alignment_signal_binding_invalid');
808
+ }
809
+ function validateWindowEntry(input) {
810
+ assertExactKeys(input, [
811
+ 'schemaVersion',
812
+ 'signalId',
813
+ 'stepId',
814
+ 'checkpoint',
815
+ 'coherenceBps',
816
+ 'uncertaintyBps',
817
+ 'contextInconsistencyBps',
818
+ 'hardViolation',
819
+ 'observedAtLogicalMs',
820
+ ], 'role alignment window entry');
821
+ if (input.schemaVersion !== 1)
822
+ throw new TypeError('role_alignment_state_invalid');
823
+ assertIdentifier(input.signalId, 'signalId');
824
+ assertIdentifier(input.stepId, 'stepId');
825
+ assertOneOf(input.checkpoint, checkpoints, 'checkpoint');
826
+ basisPoints(input.coherenceBps, 'coherenceBps');
827
+ basisPoints(input.uncertaintyBps, 'uncertaintyBps');
828
+ basisPoints(input.contextInconsistencyBps, 'contextInconsistencyBps');
829
+ if (typeof input.hardViolation !== 'boolean')
830
+ throw new TypeError('role_alignment_state_invalid');
831
+ assertSafeInteger(input.observedAtLogicalMs, 'observedAtLogicalMs');
832
+ }
833
+ function validateEvent(input, policy) {
834
+ assertExactKeys(input, [
835
+ 'schemaVersion',
836
+ 'eventSequence',
837
+ 'eventType',
838
+ 'inputDigest',
839
+ 'roleAnchorDigest',
840
+ 'signal',
841
+ 'decision',
842
+ 'reasonCode',
843
+ 'logicalTimeMs',
844
+ 'previousEventDigest',
845
+ 'eventDigest',
846
+ ], 'role alignment event');
847
+ if (input.schemaVersion !== 1)
848
+ throw new TypeError('role_alignment_event_chain_invalid');
849
+ assertSafeInteger(input.eventSequence, 'eventSequence', 1);
850
+ assertOneOf(input.eventType, [
851
+ 'signal_evaluated',
852
+ 'role_replaced',
853
+ 'session_handoff',
854
+ 'resumed',
855
+ 'closed',
856
+ ], 'eventType');
857
+ assertDigest(input.inputDigest, 'inputDigest');
858
+ assertDigest(input.roleAnchorDigest, 'roleAnchorDigest');
859
+ assertIdentifier(input.reasonCode, 'reasonCode');
860
+ assertSafeInteger(input.logicalTimeMs, 'logicalTimeMs');
861
+ if (input.previousEventDigest !== null)
862
+ assertDigest(input.previousEventDigest, 'previousEventDigest');
863
+ assertDigest(input.eventDigest, 'eventDigest');
864
+ if ((input.signal === null) !== (input.decision === null) ||
865
+ (input.eventType === 'signal_evaluated') !== (input.signal !== null))
866
+ throw new TypeError('role_alignment_event_chain_invalid');
867
+ if (input.signal !== null) {
868
+ validateSignalShape(input.signal, policy);
869
+ validateDecision(input.decision);
870
+ if (input.signal.targetDigest !== input.inputDigest ||
871
+ input.signal.roleAnchorDigest !== input.roleAnchorDigest ||
872
+ input.signal.observedAtLogicalMs !== input.logicalTimeMs ||
873
+ input.decision?.reasonCode !== input.reasonCode)
874
+ throw new TypeError('role_alignment_event_chain_invalid');
875
+ }
876
+ const { eventDigest: _ignored, ...withoutDigest } = input;
877
+ if (digestRoleAlignmentJsonV1('event', withoutDigest) !== input.eventDigest)
878
+ throw new TypeError('role_alignment_event_chain_invalid');
879
+ return input;
880
+ }
881
+ function validateDecision(input) {
882
+ assertExactKeys(input, [
883
+ 'schemaVersion',
884
+ 'disposition',
885
+ 'intervention',
886
+ 'reasonCode',
887
+ 'effectiveCoherenceBps',
888
+ 'degraded',
889
+ 'stateStatus',
890
+ ], 'role alignment decision');
891
+ if (input.schemaVersion !== 1)
892
+ throw new TypeError('role_alignment_decision_invalid');
893
+ assertOneOf(input.disposition, ['allow', 'deny', 'abstain', 'escalate'], 'disposition');
894
+ assertOneOf(input.intervention, interventions, 'intervention');
895
+ assertIdentifier(input.reasonCode, 'reasonCode');
896
+ basisPoints(input.effectiveCoherenceBps, 'effectiveCoherenceBps');
897
+ if (typeof input.degraded !== 'boolean')
898
+ throw new TypeError('role_alignment_decision_invalid');
899
+ assertOneOf(input.stateStatus, statuses, 'stateStatus');
900
+ const normalized = makeDecision(input.intervention, input.reasonCode, input.effectiveCoherenceBps, input.degraded);
901
+ if (normalized.disposition !== input.disposition ||
902
+ normalized.stateStatus !== input.stateStatus)
903
+ throw new TypeError('role_alignment_decision_invalid');
904
+ }
905
+ function validateInterventionCounts(input) {
906
+ assertExactKeys(input, ['reinforcements', 'contextChallenges', 'pauses'], 'role alignment intervention counts');
907
+ assertSafeInteger(input.reinforcements, 'reinforcements');
908
+ assertSafeInteger(input.contextChallenges, 'contextChallenges');
909
+ assertSafeInteger(input.pauses, 'pauses');
910
+ }
911
+ function chooseIntervention(input) {
912
+ const { state, signal, policy } = input;
913
+ if (signal.hardViolation ||
914
+ signal.coherenceBps <= policy.thresholds.denyCoherenceAtOrBelowBps)
915
+ return { intervention: 'deny', reasonCode: 'alignment_hard_violation' };
916
+ if (signal.checkpoint === 'pre_action' &&
917
+ input.degraded &&
918
+ policy.denyActionsWhileDegraded)
919
+ return {
920
+ intervention: 'deny',
921
+ reasonCode: 'action_denied_while_alignment_degraded',
922
+ };
923
+ if (input.consecutiveBreaches >= policy.consecutiveBreachLimit)
924
+ return {
925
+ intervention: 'request_realign',
926
+ reasonCode: 'role_realignment_required',
927
+ };
928
+ if (signal.coherenceBps <= policy.thresholds.pauseCoherenceAtOrBelowBps ||
929
+ signal.uncertaintyBps > policy.thresholds.maximumUncertaintyBps) {
930
+ if (state.interventionCounts.pauses >= policy.budgets.maximumPauses)
931
+ return {
932
+ intervention: 'request_realign',
933
+ reasonCode: 'alignment_pause_budget_exhausted',
934
+ };
935
+ return { intervention: 'pause', reasonCode: 'alignment_pause_required' };
936
+ }
937
+ if (signal.contextInconsistencyBps >=
938
+ policy.thresholds.challengeContextAtOrAboveBps) {
939
+ if (state.interventionCounts.contextChallenges >=
940
+ policy.budgets.maximumContextChallenges)
941
+ return {
942
+ intervention: 'request_realign',
943
+ reasonCode: 'context_challenge_budget_exhausted',
944
+ };
945
+ return {
946
+ intervention: 'challenge_context',
947
+ reasonCode: 'context_challenge_required',
948
+ };
949
+ }
950
+ if (input.degraded ||
951
+ input.effectiveCoherenceBps < policy.thresholds.reinforceCoherenceBelowBps) {
952
+ if (state.interventionCounts.reinforcements >=
953
+ policy.budgets.maximumReinforcements)
954
+ return {
955
+ intervention: 'request_realign',
956
+ reasonCode: 'role_reinforcement_budget_exhausted',
957
+ };
958
+ if (state.lastInterventionEventSequence !== null &&
959
+ state.revision + 1 - state.lastInterventionEventSequence <=
960
+ policy.reinforcementCooldownSignals)
961
+ return {
962
+ intervention: 'continue',
963
+ reasonCode: 'role_reinforcement_cooldown',
964
+ };
965
+ return {
966
+ intervention: 'reinforce_role',
967
+ reasonCode: 'role_reinforcement_required',
968
+ };
969
+ }
970
+ return { intervention: 'continue', reasonCode: 'alignment_healthy' };
971
+ }
972
+ function makeDecision(intervention, reasonCode, effectiveCoherenceBps, degraded) {
973
+ const disposition = intervention === 'continue' || intervention === 'reinforce_role'
974
+ ? 'allow'
975
+ : intervention === 'challenge_context' || intervention === 'pause'
976
+ ? 'abstain'
977
+ : intervention === 'request_realign'
978
+ ? 'escalate'
979
+ : 'deny';
980
+ const stateStatus = intervention === 'pause'
981
+ ? 'paused'
982
+ : intervention === 'request_realign'
983
+ ? 'realignment_required'
984
+ : intervention === 'deny'
985
+ ? 'denied'
986
+ : 'active';
987
+ return deepFreeze({
988
+ schemaVersion: 1,
989
+ disposition,
990
+ intervention,
991
+ reasonCode,
992
+ effectiveCoherenceBps,
993
+ degraded,
994
+ stateStatus,
995
+ });
996
+ }
997
+ function createEvent(input) {
998
+ const withoutDigest = {
999
+ schemaVersion: 1,
1000
+ eventSequence: input.state.revision + 1,
1001
+ eventType: input.eventType,
1002
+ inputDigest: input.inputDigest,
1003
+ roleAnchorDigest: input.roleAnchorDigest,
1004
+ signal: input.signal,
1005
+ decision: input.decision,
1006
+ reasonCode: input.reasonCode,
1007
+ logicalTimeMs: input.logicalTimeMs,
1008
+ previousEventDigest: input.state.lastEventDigest,
1009
+ };
1010
+ return deepFreeze({
1011
+ ...withoutDigest,
1012
+ eventDigest: digestRoleAlignmentJsonV1('event', withoutDigest),
1013
+ });
1014
+ }
1015
+ function withStateDigest(input) {
1016
+ const cloned = cloneJson(input);
1017
+ return deepFreeze({
1018
+ ...cloned,
1019
+ stateDigest: digestRoleAlignmentJsonV1('state', cloned),
1020
+ });
1021
+ }
1022
+ function withoutStateDigest(state) {
1023
+ const { stateDigest: _ignored, ...withoutDigest } = state;
1024
+ return withoutDigest;
1025
+ }
1026
+ function countIntervention(counts, intervention) {
1027
+ return {
1028
+ reinforcements: counts.reinforcements + (intervention === 'reinforce_role' ? 1 : 0),
1029
+ contextChallenges: counts.contextChallenges + (intervention === 'challenge_context' ? 1 : 0),
1030
+ pauses: counts.pauses + (intervention === 'pause' ? 1 : 0),
1031
+ };
1032
+ }
1033
+ function retainEvents(retained, event, policy) {
1034
+ return [...retained, event].slice(-policy.limits.maximumRetainedEvents);
1035
+ }
1036
+ function isHealthy(signal, policy) {
1037
+ return (!signal.hardViolation &&
1038
+ signal.coherenceBps >= policy.thresholds.healthyCoherenceBps &&
1039
+ signal.uncertaintyBps <= policy.thresholds.maximumUncertaintyBps &&
1040
+ signal.contextInconsistencyBps <
1041
+ policy.thresholds.challengeContextAtOrAboveBps);
1042
+ }
1043
+ function average(values) {
1044
+ if (values.length === 0)
1045
+ throw new TypeError('role_alignment_window_empty');
1046
+ return Math.floor(values.reduce((sum, value) => sum + value, 0) / values.length);
1047
+ }
1048
+ function basisPoints(value, label) {
1049
+ assertSafeInteger(value, label);
1050
+ if (value > ROLE_ALIGNMENT_BASIS_POINTS_V1)
1051
+ throw new TypeError(`${label}_out_of_range`);
1052
+ }
1053
+ function validateStringArray(input, maximum, label) {
1054
+ if (!Array.isArray(input) || input.length > maximum)
1055
+ throw new TypeError(`role_alignment_${label}_invalid`);
1056
+ for (const value of input)
1057
+ assertIdentifier(value, label);
1058
+ sortedUnique(input, label);
1059
+ }
1060
+ function requireExpectedRevision(state, expectedRevision) {
1061
+ assertSafeInteger(expectedRevision, 'expectedRevision');
1062
+ if (state.revision !== expectedRevision)
1063
+ throw new TypeError('role_alignment_revision_conflict');
1064
+ }
1065
+ function ensureStateCapacity(state, policy) {
1066
+ if (utf8ByteLength(canonicalizeControlJsonV1(state)) >
1067
+ policy.limits.maximumStateBytes)
1068
+ throw new TypeError('role_alignment_state_capacity_exhausted');
1069
+ }
1070
+ function cloneJson(input) {
1071
+ assertStrictJsonValue(input);
1072
+ return deepFreeze(JSON.parse(canonicalizeControlJsonV1(input)));
1073
+ }
1074
+ //# sourceMappingURL=role-alignment.js.map