@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,1609 @@
1
+ import { normalizeRoleBindingV1, } from "@agentplat/runtime/adapter";
2
+ import { canonicalizeControlJsonV1, utf8ByteLength } from "./canonical.js";
3
+ import { assertRoleAlignmentStateV1, } from "./role-alignment.js";
4
+ import { sha256Hex } from "./sha256.js";
5
+ import { assertDigest, assertExactKeys, assertIdentifier, assertOneOf, assertSafeInteger, assertStrictJsonValue, assertString, compareCodeUnits, deepFreeze, sortedUnique, } from "./validation.js";
6
+ export const ROLE_REALIGNMENT_SCHEMA_VERSION_V1 = 1;
7
+ export const ROLE_REALIGNMENT_BASIS_POINTS_V1 = 10_000;
8
+ const encoder = new TextEncoder();
9
+ const statuses = [
10
+ "requested",
11
+ "collecting",
12
+ "selected",
13
+ "certified",
14
+ "activating",
15
+ "activated",
16
+ "expired",
17
+ "failed",
18
+ ];
19
+ const eventTypes = [
20
+ "request_created",
21
+ "candidate_admitted",
22
+ "evaluation_recorded",
23
+ "candidate_selected",
24
+ "selection_certified",
25
+ "activation_started",
26
+ "activation_completed",
27
+ "session_rebound",
28
+ "expired",
29
+ "failed",
30
+ ];
31
+ const certificationKinds = [
32
+ "local_policy",
33
+ "collective_agreement",
34
+ ];
35
+ export function digestRoleRealignmentJsonV1(domain, value) {
36
+ return `sha256:${sha256Hex(encoder.encode(`agentplat.inference-control/role-realignment/${domain}/v1\0${canonicalizeControlJsonV1(value)}`))}`;
37
+ }
38
+ export function createRoleRealignmentPolicyRecordV1(input) {
39
+ const policy = validateRoleRealignmentPolicyV1(input);
40
+ return deepFreeze({
41
+ schemaVersion: 1,
42
+ policy,
43
+ policyDigest: digestRoleRealignmentJsonV1("policy", policy),
44
+ });
45
+ }
46
+ export function validateRoleRealignmentPolicyV1(input) {
47
+ assertExactKeys(input, [
48
+ "schemaVersion",
49
+ "policyId",
50
+ "policyVersion",
51
+ "parentPolicyDigest",
52
+ "minimumIndependentEvaluations",
53
+ "minimumCertificationWitnesses",
54
+ "thresholds",
55
+ "scoringWeights",
56
+ "limits",
57
+ ], "role realignment policy");
58
+ if (input.schemaVersion !== 1)
59
+ throw new TypeError("role_realignment_policy_invalid");
60
+ assertIdentifier(input.policyId, "policyId");
61
+ assertSafeInteger(input.policyVersion, "policyVersion", 1);
62
+ if (input.parentPolicyDigest !== null)
63
+ assertDigest(input.parentPolicyDigest, "parentPolicyDigest");
64
+ assertSafeInteger(input.minimumIndependentEvaluations, "minimumIndependentEvaluations", 1);
65
+ assertSafeInteger(input.minimumCertificationWitnesses, "minimumCertificationWitnesses", 1);
66
+ validateThresholds(input.thresholds);
67
+ validateWeights(input.scoringWeights);
68
+ validateLimits(input.limits);
69
+ if (input.minimumIndependentEvaluations >
70
+ input.limits.maximumEvaluationsPerCandidate ||
71
+ input.minimumCertificationWitnesses > 128)
72
+ throw new TypeError("role_realignment_policy_limits_invalid");
73
+ return freezeClone(input);
74
+ }
75
+ export function createRoleAuthorityCeilingV1(input) {
76
+ const withoutDigest = normalizeAuthorityCeiling(input);
77
+ return deepFreeze({
78
+ ...withoutDigest,
79
+ ceilingDigest: digestRoleRealignmentJsonV1("authority", withoutDigest),
80
+ });
81
+ }
82
+ export function validateRoleAuthorityCeilingV1(input, policy) {
83
+ assertExactKeys(input, [
84
+ "schemaVersion",
85
+ "mandateDigest",
86
+ "capabilityKeys",
87
+ "resourceClasses",
88
+ "maximumActionBudgetUnits",
89
+ "validUntilLogicalMs",
90
+ "ceilingDigest",
91
+ ], "role authority ceiling");
92
+ const { ceilingDigest, ...body } = input;
93
+ assertDigest(ceilingDigest, "ceilingDigest");
94
+ const normalized = normalizeAuthorityCeiling(body);
95
+ if (canonicalizeControlJsonV1(normalized) !==
96
+ canonicalizeControlJsonV1(body) ||
97
+ digestRoleRealignmentJsonV1("authority", body) !==
98
+ ceilingDigest)
99
+ throw new TypeError("role_authority_ceiling_invalid");
100
+ if (policy &&
101
+ (input.capabilityKeys.length > policy.limits.maximumCapabilities ||
102
+ input.resourceClasses.length > policy.limits.maximumResourceClasses))
103
+ throw new TypeError("role_realignment_capacity_exhausted");
104
+ return freezeClone(input);
105
+ }
106
+ export function createTrustedRoleDefinitionV1(input) {
107
+ const body = normalizeRoleDefinition({ schemaVersion: 1, ...input });
108
+ return deepFreeze({
109
+ ...body,
110
+ definitionDigest: digestRoleRealignmentJsonV1("definition", body),
111
+ });
112
+ }
113
+ export function validateTrustedRoleDefinitionV1(input, policy) {
114
+ assertExactKeys(input, [
115
+ "schemaVersion",
116
+ "catalogId",
117
+ "definitionId",
118
+ "definitionRevision",
119
+ "predecessorDefinitionDigest",
120
+ "roleKey",
121
+ "instructions",
122
+ "constraints",
123
+ "requiredCapabilityKeys",
124
+ "requiredResourceClasses",
125
+ "maximumActionBudgetUnits",
126
+ "validFromLogicalMs",
127
+ "validUntilLogicalMs",
128
+ "definitionDigest",
129
+ ], "trusted role definition");
130
+ const { definitionDigest, ...body } = input;
131
+ assertDigest(definitionDigest, "definitionDigest");
132
+ const normalized = normalizeRoleDefinition(body);
133
+ if (canonicalizeControlJsonV1(normalized) !==
134
+ canonicalizeControlJsonV1(body) ||
135
+ digestRoleRealignmentJsonV1("definition", body) !==
136
+ definitionDigest)
137
+ throw new TypeError("role_definition_invalid");
138
+ if (input.instructions.length > policy.limits.maximumInstructions ||
139
+ input.instructions.some((value) => utf8ByteLength(value) > policy.limits.maximumInstructionBytes) ||
140
+ input.requiredCapabilityKeys.length > policy.limits.maximumCapabilities ||
141
+ input.requiredResourceClasses.length >
142
+ policy.limits.maximumResourceClasses ||
143
+ utf8ByteLength(canonicalizeControlJsonV1(input.constraints)) >
144
+ policy.limits.maximumConstraintsBytes)
145
+ throw new TypeError("role_realignment_capacity_exhausted");
146
+ return freezeClone(input);
147
+ }
148
+ export function createRoleRealignmentRequestV1(input) {
149
+ assertIdentifier(input.requestId, "requestId");
150
+ const policyRecord = createRoleRealignmentPolicyRecordV1(input.policy);
151
+ assertRoleAlignmentStateV1(input.alignmentState, input.alignmentPolicy);
152
+ if (input.alignmentState.status !== "realignment_required" ||
153
+ input.alignmentState.lastEventDigest === null)
154
+ throw new TypeError("role_realignment_not_required");
155
+ const authorityCeiling = validateRoleAuthorityCeilingV1(input.authorityCeiling, policyRecord.policy);
156
+ assertSafeInteger(input.createdAtLogicalMs, "createdAtLogicalMs");
157
+ assertSafeInteger(input.expiresAtLogicalMs, "expiresAtLogicalMs", 1);
158
+ if (input.createdAtLogicalMs < input.alignmentState.lastLogicalTimeMs ||
159
+ input.expiresAtLogicalMs <= input.createdAtLogicalMs ||
160
+ input.expiresAtLogicalMs - input.createdAtLogicalMs >
161
+ policyRecord.policy.limits.maximumRequestTtlMs ||
162
+ input.expiresAtLogicalMs > authorityCeiling.validUntilLogicalMs)
163
+ throw new TypeError("role_realignment_request_lifetime_invalid");
164
+ const state = input.alignmentState;
165
+ const body = {
166
+ schemaVersion: 1,
167
+ requestId: input.requestId,
168
+ policyId: policyRecord.policy.policyId,
169
+ policyVersion: policyRecord.policy.policyVersion,
170
+ policyDigest: policyRecord.policyDigest,
171
+ tenantId: state.tenantId,
172
+ sessionId: state.sessionId,
173
+ agentId: state.agentId,
174
+ objectiveId: state.objectiveId,
175
+ alignmentControllerId: state.controllerId,
176
+ alignmentControllerVersion: state.controllerVersion,
177
+ alignmentImplementationId: state.implementationId,
178
+ alignmentPolicyDigest: state.policyDigest,
179
+ alignmentStateRevision: state.revision,
180
+ alignmentStateDigest: state.stateDigest,
181
+ triggerEventDigest: state.lastEventDigest,
182
+ currentRoleAnchorDigest: state.roleAnchor.anchorDigest,
183
+ currentRoleBindingId: state.roleAnchor.roleBindingId,
184
+ currentRoleRevision: state.roleAnchor.roleRevision,
185
+ currentRoleContentDigest: state.roleAnchor.roleContentDigest,
186
+ authorityCeiling,
187
+ createdAtLogicalMs: input.createdAtLogicalMs,
188
+ expiresAtLogicalMs: input.expiresAtLogicalMs,
189
+ };
190
+ return deepFreeze({
191
+ ...body,
192
+ requestDigest: digestRoleRealignmentJsonV1("request", body),
193
+ });
194
+ }
195
+ export function validateRoleRealignmentRequestV1(input, policy) {
196
+ assertExactKeys(input, [
197
+ "schemaVersion",
198
+ "requestId",
199
+ "policyId",
200
+ "policyVersion",
201
+ "policyDigest",
202
+ "tenantId",
203
+ "sessionId",
204
+ "agentId",
205
+ "objectiveId",
206
+ "alignmentControllerId",
207
+ "alignmentControllerVersion",
208
+ "alignmentImplementationId",
209
+ "alignmentPolicyDigest",
210
+ "alignmentStateRevision",
211
+ "alignmentStateDigest",
212
+ "triggerEventDigest",
213
+ "currentRoleAnchorDigest",
214
+ "currentRoleBindingId",
215
+ "currentRoleRevision",
216
+ "currentRoleContentDigest",
217
+ "authorityCeiling",
218
+ "createdAtLogicalMs",
219
+ "expiresAtLogicalMs",
220
+ "requestDigest",
221
+ ], "role realignment request");
222
+ if (input.schemaVersion !== 1)
223
+ throw new TypeError("role_realignment_request_invalid");
224
+ for (const [label, value] of [
225
+ ["requestId", input.requestId],
226
+ ["tenantId", input.tenantId],
227
+ ["sessionId", input.sessionId],
228
+ ["agentId", input.agentId],
229
+ ["objectiveId", input.objectiveId],
230
+ ["alignmentControllerId", input.alignmentControllerId],
231
+ ["alignmentImplementationId", input.alignmentImplementationId],
232
+ ["currentRoleBindingId", input.currentRoleBindingId],
233
+ ])
234
+ assertIdentifier(value, label);
235
+ for (const [label, value] of [
236
+ ["policyVersion", input.policyVersion],
237
+ ["alignmentControllerVersion", input.alignmentControllerVersion],
238
+ ["alignmentStateRevision", input.alignmentStateRevision],
239
+ ["currentRoleRevision", input.currentRoleRevision],
240
+ ["createdAtLogicalMs", input.createdAtLogicalMs],
241
+ ["expiresAtLogicalMs", input.expiresAtLogicalMs],
242
+ ])
243
+ assertSafeInteger(value, label, label === "createdAtLogicalMs" ? 0 : 1);
244
+ for (const [label, value] of [
245
+ ["policyDigest", input.policyDigest],
246
+ ["alignmentPolicyDigest", input.alignmentPolicyDigest],
247
+ ["alignmentStateDigest", input.alignmentStateDigest],
248
+ ["triggerEventDigest", input.triggerEventDigest],
249
+ ["currentRoleAnchorDigest", input.currentRoleAnchorDigest],
250
+ ["currentRoleContentDigest", input.currentRoleContentDigest],
251
+ ["requestDigest", input.requestDigest],
252
+ ])
253
+ assertDigest(value, label);
254
+ const policyRecord = createRoleRealignmentPolicyRecordV1(policy);
255
+ validateRoleAuthorityCeilingV1(input.authorityCeiling, policyRecord.policy);
256
+ const { requestDigest, ...body } = input;
257
+ if (input.policyId !== policyRecord.policy.policyId ||
258
+ input.policyVersion !== policyRecord.policy.policyVersion ||
259
+ input.policyDigest !== policyRecord.policyDigest ||
260
+ input.expiresAtLogicalMs <= input.createdAtLogicalMs ||
261
+ input.expiresAtLogicalMs - input.createdAtLogicalMs >
262
+ policyRecord.policy.limits.maximumRequestTtlMs ||
263
+ input.expiresAtLogicalMs > input.authorityCeiling.validUntilLogicalMs ||
264
+ digestRoleRealignmentJsonV1("request", body) !==
265
+ requestDigest)
266
+ throw new TypeError("role_realignment_request_invalid");
267
+ return freezeClone(input);
268
+ }
269
+ export function createRoleCandidateProposalV1(input) {
270
+ const body = normalizeProposal({ schemaVersion: 1, ...input });
271
+ return deepFreeze({
272
+ ...body,
273
+ proposalDigest: digestRoleRealignmentJsonV1("proposal", body),
274
+ });
275
+ }
276
+ export function validateRoleCandidateProposalV1(input, request, policy) {
277
+ assertExactKeys(input, [
278
+ "schemaVersion",
279
+ "proposalId",
280
+ "requestDigest",
281
+ "proposerId",
282
+ "proposerVersion",
283
+ "proposerBindingDigest",
284
+ "definitionId",
285
+ "definitionRevision",
286
+ "definitionDigest",
287
+ "reasonCodes",
288
+ "evidenceReferenceIds",
289
+ "proposedAtLogicalMs",
290
+ "expiresAtLogicalMs",
291
+ "proposalDigest",
292
+ ], "role candidate proposal");
293
+ const { proposalDigest, ...body } = input;
294
+ assertDigest(proposalDigest, "proposalDigest");
295
+ const normalized = normalizeProposal(body);
296
+ if (canonicalizeControlJsonV1(normalized) !==
297
+ canonicalizeControlJsonV1(body) ||
298
+ input.requestDigest !== request.requestDigest ||
299
+ input.proposedAtLogicalMs < request.createdAtLogicalMs ||
300
+ input.expiresAtLogicalMs > request.expiresAtLogicalMs ||
301
+ input.reasonCodes.length > policy.limits.maximumReasonCodes ||
302
+ input.evidenceReferenceIds.length >
303
+ policy.limits.maximumEvidenceReferences ||
304
+ digestRoleRealignmentJsonV1("proposal", body) !==
305
+ proposalDigest)
306
+ throw new TypeError("role_candidate_proposal_invalid");
307
+ return freezeClone(input);
308
+ }
309
+ export function createRoleCandidateEvaluationV1(input) {
310
+ const body = normalizeEvaluation({ schemaVersion: 1, ...input });
311
+ return deepFreeze({
312
+ ...body,
313
+ evaluationDigest: digestRoleRealignmentJsonV1("evaluation", body),
314
+ });
315
+ }
316
+ export function validateRoleCandidateEvaluationV1(input, state, policy) {
317
+ assertExactKeys(input, [
318
+ "schemaVersion",
319
+ "evaluationId",
320
+ "requestDigest",
321
+ "candidateDigest",
322
+ "definitionDigest",
323
+ "evaluatorId",
324
+ "evaluatorVersion",
325
+ "evaluatorBindingDigest",
326
+ "eligibilityDecisionDigest",
327
+ "eligible",
328
+ "roleFitBps",
329
+ "missionContributionBps",
330
+ "uncertaintyBps",
331
+ "transitionRiskBps",
332
+ "reasonCodes",
333
+ "evidenceReferenceIds",
334
+ "evaluatedAtLogicalMs",
335
+ "expiresAtLogicalMs",
336
+ "evaluationDigest",
337
+ ], "role candidate evaluation");
338
+ const { evaluationDigest, ...body } = input;
339
+ assertDigest(evaluationDigest, "evaluationDigest");
340
+ const normalized = normalizeEvaluation(body);
341
+ const candidate = state.candidates.find((item) => item.candidateDigest === input.candidateDigest);
342
+ if (canonicalizeControlJsonV1(normalized) !==
343
+ canonicalizeControlJsonV1(body) ||
344
+ !candidate ||
345
+ input.requestDigest !== state.request.requestDigest ||
346
+ input.definitionDigest !== candidate.proposal.definitionDigest ||
347
+ input.evaluatedAtLogicalMs < candidate.admittedAtLogicalMs ||
348
+ input.expiresAtLogicalMs > state.request.expiresAtLogicalMs ||
349
+ input.expiresAtLogicalMs - input.evaluatedAtLogicalMs >
350
+ policy.limits.maximumEvaluationTtlMs ||
351
+ input.reasonCodes.length > policy.limits.maximumReasonCodes ||
352
+ input.evidenceReferenceIds.length >
353
+ policy.limits.maximumEvidenceReferences ||
354
+ digestRoleRealignmentJsonV1("evaluation", body) !==
355
+ evaluationDigest)
356
+ throw new TypeError("role_candidate_evaluation_invalid");
357
+ return freezeClone(input);
358
+ }
359
+ export function createRoleRealignmentStateV1(input) {
360
+ assertIdentifier(input.controllerId, "controllerId");
361
+ assertSafeInteger(input.controllerVersion, "controllerVersion", 1);
362
+ assertIdentifier(input.implementationId, "implementationId");
363
+ const policyRecord = createRoleRealignmentPolicyRecordV1(input.policy);
364
+ const request = validateRoleRealignmentRequestV1(input.request, policyRecord.policy);
365
+ assertSafeInteger(input.createdAtLogicalMs, "createdAtLogicalMs");
366
+ if (input.createdAtLogicalMs < request.createdAtLogicalMs ||
367
+ input.createdAtLogicalMs >= request.expiresAtLogicalMs)
368
+ throw new TypeError("role_realignment_request_expired");
369
+ const event = createRoleRealignmentEventV1({
370
+ eventSequence: 1,
371
+ eventType: "request_created",
372
+ inputDigest: request.requestDigest,
373
+ reasonCode: "role_realignment_requested",
374
+ logicalTimeMs: input.createdAtLogicalMs,
375
+ previousEventDigest: null,
376
+ });
377
+ const state = withRoleRealignmentStateDigestV1({
378
+ schemaVersion: 1,
379
+ controllerId: input.controllerId,
380
+ controllerVersion: input.controllerVersion,
381
+ implementationId: input.implementationId,
382
+ policyId: policyRecord.policy.policyId,
383
+ policyVersion: policyRecord.policy.policyVersion,
384
+ policyDigest: policyRecord.policyDigest,
385
+ originSessionId: request.sessionId,
386
+ activeSessionId: request.sessionId,
387
+ originAgentId: request.agentId,
388
+ activeAgentId: request.agentId,
389
+ activeRoleAnchorDigest: request.currentRoleAnchorDigest,
390
+ tenantId: request.tenantId,
391
+ objectiveId: request.objectiveId,
392
+ request,
393
+ status: "requested",
394
+ revision: 1,
395
+ candidates: [],
396
+ evaluations: [],
397
+ selection: null,
398
+ certificate: null,
399
+ activation: null,
400
+ lastLogicalTimeMs: input.createdAtLogicalMs,
401
+ lastEventDigest: event.eventDigest,
402
+ events: [event],
403
+ });
404
+ ensureRoleRealignmentStateCapacityV1(state, policyRecord.policy);
405
+ return state;
406
+ }
407
+ export function admitRoleCandidateV1(stateInput, input, policyInput) {
408
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
409
+ const state = stateInput;
410
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
411
+ requireRoleRealignmentOpenV1(state, ["requested", "collecting"]);
412
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs);
413
+ const proposal = validateRoleCandidateProposalV1(input.proposal, state.request, policy);
414
+ assertDigest(input.proposerEligibilityDecisionDigest, "proposerEligibilityDecisionDigest");
415
+ const definition = validateTrustedRoleDefinitionV1(input.definition, policy);
416
+ if (proposal.definitionId !== definition.definitionId ||
417
+ proposal.definitionRevision !== definition.definitionRevision ||
418
+ proposal.definitionDigest !== definition.definitionDigest ||
419
+ proposal.expiresAtLogicalMs <= input.logicalTimeMs ||
420
+ definition.validFromLogicalMs > input.logicalTimeMs ||
421
+ definition.validUntilLogicalMs <= input.logicalTimeMs)
422
+ throw new TypeError("role_candidate_definition_binding_invalid");
423
+ assertTrustedRoleDefinitionWithinAuthorityCeilingV1(definition, state.request.authorityCeiling);
424
+ if (state.candidates.some(({ proposal: admitted }) => admitted.proposalId === proposal.proposalId ||
425
+ admitted.proposalDigest === proposal.proposalDigest))
426
+ throw new TypeError("role_candidate_proposal_already_admitted");
427
+ if (state.candidates.some(({ proposal: admitted }) => admitted.definitionDigest === definition.definitionDigest))
428
+ throw new TypeError("role_candidate_definition_already_admitted");
429
+ const proposerBindings = new Set(state.candidates.map(({ proposal: item }) => item.proposerBindingDigest));
430
+ proposerBindings.add(proposal.proposerBindingDigest);
431
+ if (state.candidates.length >= policy.limits.maximumCandidates ||
432
+ proposerBindings.size > policy.limits.maximumProposers)
433
+ throw new TypeError("role_realignment_capacity_exhausted");
434
+ const candidateBody = {
435
+ schemaVersion: 1,
436
+ candidateId: `candidate-${proposal.proposalDigest.slice(7, 39)}`,
437
+ requestDigest: state.request.requestDigest,
438
+ proposal,
439
+ proposerEligibilityDecisionDigest: input.proposerEligibilityDecisionDigest,
440
+ catalogId: definition.catalogId,
441
+ admittedAtLogicalMs: input.logicalTimeMs,
442
+ };
443
+ const candidate = deepFreeze({
444
+ ...candidateBody,
445
+ candidateDigest: digestRoleRealignmentJsonV1("candidate", candidateBody),
446
+ });
447
+ const candidates = [...state.candidates, candidate].sort((left, right) => compareCodeUnits(left.candidateDigest, right.candidateDigest));
448
+ return transitionRoleRealignmentStateV1({
449
+ state,
450
+ policy,
451
+ eventType: "candidate_admitted",
452
+ inputDigest: candidate.candidateDigest,
453
+ reasonCode: "trusted_role_candidate_admitted",
454
+ logicalTimeMs: input.logicalTimeMs,
455
+ patch: { status: "collecting", candidates },
456
+ });
457
+ }
458
+ export function recordRoleCandidateEvaluationV1(stateInput, input, policyInput) {
459
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
460
+ const state = stateInput;
461
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
462
+ requireRoleRealignmentOpenV1(state, ["collecting"]);
463
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs);
464
+ const evaluation = validateRoleCandidateEvaluationV1(input.evaluation, state, policy);
465
+ if (evaluation.evaluatedAtLogicalMs > input.logicalTimeMs ||
466
+ evaluation.expiresAtLogicalMs <= input.logicalTimeMs)
467
+ throw new TypeError("role_candidate_evaluation_expired");
468
+ const forCandidate = state.evaluations.filter(({ candidateDigest }) => candidateDigest === evaluation.candidateDigest);
469
+ if (state.evaluations.some(({ evaluationId, evaluationDigest }) => evaluationId === evaluation.evaluationId ||
470
+ evaluationDigest === evaluation.evaluationDigest) ||
471
+ forCandidate.some(({ evaluatorBindingDigest }) => evaluatorBindingDigest === evaluation.evaluatorBindingDigest))
472
+ throw new TypeError("role_candidate_evaluation_already_recorded");
473
+ if (forCandidate.length >= policy.limits.maximumEvaluationsPerCandidate)
474
+ throw new TypeError("role_realignment_capacity_exhausted");
475
+ const evaluations = [...state.evaluations, evaluation].sort((left, right) => compareCodeUnits(left.evaluationDigest, right.evaluationDigest));
476
+ return transitionRoleRealignmentStateV1({
477
+ state,
478
+ policy,
479
+ eventType: "evaluation_recorded",
480
+ inputDigest: evaluation.evaluationDigest,
481
+ reasonCode: evaluation.eligible
482
+ ? "candidate_evaluation_eligible"
483
+ : "candidate_evaluation_ineligible",
484
+ logicalTimeMs: input.logicalTimeMs,
485
+ patch: { evaluations },
486
+ });
487
+ }
488
+ export function selectRoleCandidateV1(stateInput, input, policyInput) {
489
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
490
+ const state = stateInput;
491
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
492
+ requireRoleRealignmentOpenV1(state, ["collecting"]);
493
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs);
494
+ assertIdentifier(input.selectionId, "selectionId");
495
+ const aggregates = state.candidates
496
+ .map((candidate) => aggregateRoleCandidateV1(candidate, state.evaluations, policy, input.logicalTimeMs))
497
+ .filter((item) => item !== null)
498
+ .sort((left, right) => compareCodeUnits(left.candidateDigest, right.candidateDigest));
499
+ if (!aggregates.length)
500
+ throw new TypeError("role_realignment_no_eligible_candidate");
501
+ const ranked = [...aggregates].sort((left, right) => right.aggregateScore - left.aggregateScore ||
502
+ compareCodeUnits(left.definitionDigest, right.definitionDigest) ||
503
+ compareCodeUnits(left.candidateDigest, right.candidateDigest));
504
+ const selected = ranked[0];
505
+ const body = {
506
+ schemaVersion: 1,
507
+ selectionId: input.selectionId,
508
+ requestDigest: state.request.requestDigest,
509
+ stateRevision: state.revision,
510
+ aggregates,
511
+ selectedCandidateId: selected.candidateId,
512
+ selectedCandidateDigest: selected.candidateDigest,
513
+ selectedDefinitionDigest: selected.definitionDigest,
514
+ selectedAtLogicalMs: input.logicalTimeMs,
515
+ };
516
+ const selection = deepFreeze({
517
+ ...body,
518
+ selectionDigest: digestRoleRealignmentJsonV1("selection", body),
519
+ });
520
+ return transitionRoleRealignmentStateV1({
521
+ state,
522
+ policy,
523
+ eventType: "candidate_selected",
524
+ inputDigest: selection.selectionDigest,
525
+ reasonCode: "candidate_selected_deterministically",
526
+ logicalTimeMs: input.logicalTimeMs,
527
+ patch: { status: "selected", selection },
528
+ });
529
+ }
530
+ export function createRoleRealignmentCertificateV1(input) {
531
+ const body = normalizeCertificate({ schemaVersion: 1, ...input });
532
+ return deepFreeze({
533
+ ...body,
534
+ certificateDigest: digestRoleRealignmentJsonV1("certificate", body),
535
+ });
536
+ }
537
+ export function validateRoleRealignmentCertificateV1(input, state, policy) {
538
+ assertExactKeys(input, [
539
+ "schemaVersion",
540
+ "certificateId",
541
+ "certificationKind",
542
+ "certifierId",
543
+ "certifierVersion",
544
+ "certifierBindingDigest",
545
+ "requestDigest",
546
+ "selectionDigest",
547
+ "selectedCandidateDigest",
548
+ "selectedDefinitionDigest",
549
+ "authorityCeilingDigest",
550
+ "witnessIds",
551
+ "membershipEpoch",
552
+ "membershipConfigurationDigest",
553
+ "sourceCertificateDigest",
554
+ "certifiedAtLogicalMs",
555
+ "expiresAtLogicalMs",
556
+ "certificateDigest",
557
+ ], "role realignment certificate");
558
+ if (!state.selection)
559
+ throw new TypeError("role_realignment_selection_required");
560
+ const { certificateDigest, ...body } = input;
561
+ assertDigest(certificateDigest, "certificateDigest");
562
+ const normalized = normalizeCertificate(body);
563
+ if (canonicalizeControlJsonV1(normalized) !==
564
+ canonicalizeControlJsonV1(body) ||
565
+ input.requestDigest !== state.request.requestDigest ||
566
+ input.selectionDigest !== state.selection.selectionDigest ||
567
+ input.selectedCandidateDigest !== state.selection.selectedCandidateDigest ||
568
+ input.selectedDefinitionDigest !==
569
+ state.selection.selectedDefinitionDigest ||
570
+ input.authorityCeilingDigest !==
571
+ state.request.authorityCeiling.ceilingDigest ||
572
+ input.witnessIds.length < policy.minimumCertificationWitnesses ||
573
+ input.certifiedAtLogicalMs < state.selection.selectedAtLogicalMs ||
574
+ input.expiresAtLogicalMs > state.request.expiresAtLogicalMs ||
575
+ input.expiresAtLogicalMs - input.certifiedAtLogicalMs >
576
+ policy.limits.maximumCertificationTtlMs ||
577
+ digestRoleRealignmentJsonV1("certificate", body) !==
578
+ certificateDigest)
579
+ throw new TypeError("role_realignment_certificate_invalid");
580
+ return freezeClone(input);
581
+ }
582
+ export function certifyRoleRealignmentSelectionV1(stateInput, input, policyInput) {
583
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
584
+ const state = stateInput;
585
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
586
+ requireRoleRealignmentOpenV1(state, ["selected"]);
587
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs);
588
+ const certificate = validateRoleRealignmentCertificateV1(input.certificate, state, policy);
589
+ if (certificate.certifiedAtLogicalMs > input.logicalTimeMs ||
590
+ certificate.expiresAtLogicalMs <= input.logicalTimeMs)
591
+ throw new TypeError("role_realignment_certificate_expired");
592
+ return transitionRoleRealignmentStateV1({
593
+ state,
594
+ policy,
595
+ eventType: "selection_certified",
596
+ inputDigest: certificate.certificateDigest,
597
+ reasonCode: "selection_certified",
598
+ logicalTimeMs: input.logicalTimeMs,
599
+ patch: { status: "certified", certificate },
600
+ });
601
+ }
602
+ export function materializeCertifiedRoleBindingV1(stateInput, input, policyInput) {
603
+ assertRoleRealignmentStateV1(stateInput, policyInput);
604
+ const state = stateInput;
605
+ requireRoleRealignmentOpenV1(state, ["certified", "activating"]);
606
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs);
607
+ if (!state.selection ||
608
+ !state.certificate ||
609
+ state.certificate.expiresAtLogicalMs <= input.logicalTimeMs)
610
+ throw new TypeError("role_realignment_certificate_expired");
611
+ const candidate = state.candidates.find(({ candidateDigest }) => candidateDigest === state.selection.selectedCandidateDigest);
612
+ if (!candidate)
613
+ throw new TypeError("role_realignment_selected_candidate_missing");
614
+ const definition = validateTrustedRoleDefinitionV1(input.definition, policyInput);
615
+ if (candidate.catalogId !== definition.catalogId ||
616
+ candidate.proposal.definitionId !== definition.definitionId ||
617
+ candidate.proposal.definitionRevision !== definition.definitionRevision ||
618
+ candidate.proposal.definitionDigest !== definition.definitionDigest ||
619
+ state.selection.selectedDefinitionDigest !== definition.definitionDigest)
620
+ throw new TypeError("role_realignment_selected_definition_mismatch");
621
+ assertTrustedRoleDefinitionWithinAuthorityCeilingV1(definition, state.request.authorityCeiling);
622
+ const validFromLogicalMs = Math.max(input.logicalTimeMs, definition.validFromLogicalMs);
623
+ const validUntilLogicalMs = Math.min(definition.validUntilLogicalMs, state.request.expiresAtLogicalMs, state.request.authorityCeiling.validUntilLogicalMs);
624
+ if (validUntilLogicalMs <= validFromLogicalMs)
625
+ throw new TypeError("role_realignment_role_expired");
626
+ return normalizeRoleBindingV1({
627
+ schemaVersion: 1,
628
+ roleBindingId: `role-${definition.definitionDigest.slice(7, 39)}`,
629
+ roleRevision: state.request.currentRoleRevision + 1,
630
+ predecessorRoleBindingId: state.request.currentRoleBindingId,
631
+ objectiveId: state.objectiveId,
632
+ roleKey: definition.roleKey,
633
+ instructions: definition.instructions,
634
+ constraints: definition.constraints,
635
+ validFromLogicalMs,
636
+ validUntilLogicalMs,
637
+ });
638
+ }
639
+ export function beginRoleRealignmentActivationV1(stateInput, input, policyInput) {
640
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
641
+ const state = stateInput;
642
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
643
+ requireRoleRealignmentOpenV1(state, ["certified"]);
644
+ assertIdentifier(input.activationId, "activationId");
645
+ const roleBinding = materializeCertifiedRoleBindingV1(state, input, policy);
646
+ const roleBindingDigest = digestRoleRealignmentJsonV1("role_binding", roleBinding);
647
+ const body = {
648
+ schemaVersion: 1,
649
+ activationId: input.activationId,
650
+ requestDigest: state.request.requestDigest,
651
+ selectionDigest: state.selection.selectionDigest,
652
+ certificateDigest: state.certificate.certificateDigest,
653
+ definition: input.definition,
654
+ roleBinding,
655
+ roleBindingDigest,
656
+ startedAtLogicalMs: input.logicalTimeMs,
657
+ completedAtLogicalMs: null,
658
+ runtimeSessionRevision: null,
659
+ alignmentStateRevision: null,
660
+ alignmentRoleAnchorDigest: null,
661
+ };
662
+ const activation = deepFreeze({
663
+ ...body,
664
+ activationDigest: digestRoleRealignmentJsonV1("activation", body),
665
+ });
666
+ return transitionRoleRealignmentStateV1({
667
+ state,
668
+ policy,
669
+ eventType: "activation_started",
670
+ inputDigest: activation.activationDigest,
671
+ reasonCode: "certified_role_activation_started",
672
+ logicalTimeMs: input.logicalTimeMs,
673
+ patch: { status: "activating", activation },
674
+ });
675
+ }
676
+ export function completeRoleRealignmentActivationV1(stateInput, input, policyInput) {
677
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
678
+ const state = stateInput;
679
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
680
+ requireRoleRealignmentOpenV1(state, ["activating"]);
681
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs);
682
+ if (!state.activation)
683
+ throw new TypeError("role_realignment_activation_missing");
684
+ assertSafeInteger(input.runtimeSessionRevision, "runtimeSessionRevision", 1);
685
+ assertSafeInteger(input.alignmentStateRevision, "alignmentStateRevision", 1);
686
+ assertDigest(input.alignmentRoleAnchorDigest, "alignmentRoleAnchorDigest");
687
+ const { activationDigest: _ignored, ...previous } = state.activation;
688
+ const body = {
689
+ ...previous,
690
+ completedAtLogicalMs: input.logicalTimeMs,
691
+ runtimeSessionRevision: input.runtimeSessionRevision,
692
+ alignmentStateRevision: input.alignmentStateRevision,
693
+ alignmentRoleAnchorDigest: input.alignmentRoleAnchorDigest,
694
+ };
695
+ const activation = deepFreeze({
696
+ ...body,
697
+ activationDigest: digestRoleRealignmentJsonV1("activation", body),
698
+ });
699
+ return transitionRoleRealignmentStateV1({
700
+ state,
701
+ policy,
702
+ eventType: "activation_completed",
703
+ inputDigest: activation.activationDigest,
704
+ reasonCode: "certified_role_activated",
705
+ logicalTimeMs: input.logicalTimeMs,
706
+ patch: {
707
+ status: "activated",
708
+ activation,
709
+ activeRoleAnchorDigest: input.alignmentRoleAnchorDigest,
710
+ },
711
+ });
712
+ }
713
+ export function rebindRoleRealignmentSessionV1(stateInput, input, policyInput) {
714
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
715
+ const state = stateInput;
716
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
717
+ requireRoleRealignmentOpenV1(state, [
718
+ "requested",
719
+ "collecting",
720
+ "selected",
721
+ "certified",
722
+ "activating",
723
+ "activated",
724
+ ]);
725
+ const terminalContinuity = state.status === "activated";
726
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs, terminalContinuity);
727
+ assertIdentifier(input.targetSessionId, "targetSessionId");
728
+ assertIdentifier(input.targetAgentId, "targetAgentId");
729
+ assertDigest(input.targetRoleAnchorDigest, "targetRoleAnchorDigest");
730
+ assertDigest(input.transferDigest, "transferDigest");
731
+ if (input.targetSessionId === state.activeSessionId)
732
+ throw new TypeError("role_realignment_handoff_invalid");
733
+ return transitionRoleRealignmentStateV1({
734
+ state,
735
+ policy,
736
+ eventType: "session_rebound",
737
+ inputDigest: digestRoleRealignmentJsonV1("handoff", {
738
+ transferDigest: input.transferDigest,
739
+ sourceSessionId: state.activeSessionId,
740
+ targetSessionId: input.targetSessionId,
741
+ targetAgentId: input.targetAgentId,
742
+ targetRoleAnchorDigest: input.targetRoleAnchorDigest,
743
+ }),
744
+ reasonCode: "role_realignment_session_rebound",
745
+ logicalTimeMs: input.logicalTimeMs,
746
+ patch: {
747
+ activeSessionId: input.targetSessionId,
748
+ activeAgentId: input.targetAgentId,
749
+ activeRoleAnchorDigest: input.targetRoleAnchorDigest,
750
+ },
751
+ permitExpiredTime: terminalContinuity,
752
+ });
753
+ }
754
+ export function expireRoleRealignmentV1(stateInput, input, policyInput) {
755
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
756
+ const state = stateInput;
757
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
758
+ requireRoleRealignmentOpenV1(state, [
759
+ "requested",
760
+ "collecting",
761
+ "selected",
762
+ "certified",
763
+ "activating",
764
+ ]);
765
+ assertSafeInteger(input.logicalTimeMs, "logicalTimeMs");
766
+ if (input.logicalTimeMs < state.request.expiresAtLogicalMs)
767
+ throw new TypeError("role_realignment_not_expired");
768
+ return transitionRoleRealignmentStateV1({
769
+ state,
770
+ policy,
771
+ eventType: "expired",
772
+ inputDigest: state.request.requestDigest,
773
+ reasonCode: "role_realignment_expired",
774
+ logicalTimeMs: input.logicalTimeMs,
775
+ patch: { status: "expired" },
776
+ permitExpiredTime: true,
777
+ });
778
+ }
779
+ export function failRoleRealignmentV1(stateInput, input, policyInput) {
780
+ const policy = assertRoleRealignmentStateV1(stateInput, policyInput);
781
+ const state = stateInput;
782
+ requireRoleRealignmentRevisionV1(state, input.expectedRevision);
783
+ requireRoleRealignmentOpenV1(state, [
784
+ "requested",
785
+ "collecting",
786
+ "selected",
787
+ "certified",
788
+ "activating",
789
+ ]);
790
+ requireRoleRealignmentTimeV1(state, input.logicalTimeMs, true);
791
+ assertIdentifier(input.reasonCode, "reasonCode");
792
+ assertDigest(input.failureDigest, "failureDigest");
793
+ return transitionRoleRealignmentStateV1({
794
+ state,
795
+ policy,
796
+ eventType: "failed",
797
+ inputDigest: input.failureDigest,
798
+ reasonCode: input.reasonCode,
799
+ logicalTimeMs: input.logicalTimeMs,
800
+ patch: { status: "failed" },
801
+ permitExpiredTime: true,
802
+ });
803
+ }
804
+ export function assertRoleRealignmentStateV1(input, policyInput, binding = {}) {
805
+ const policyRecord = createRoleRealignmentPolicyRecordV1(policyInput);
806
+ assertExactKeys(input, [
807
+ "schemaVersion",
808
+ "controllerId",
809
+ "controllerVersion",
810
+ "implementationId",
811
+ "policyId",
812
+ "policyVersion",
813
+ "policyDigest",
814
+ "originSessionId",
815
+ "activeSessionId",
816
+ "originAgentId",
817
+ "activeAgentId",
818
+ "activeRoleAnchorDigest",
819
+ "tenantId",
820
+ "objectiveId",
821
+ "request",
822
+ "status",
823
+ "revision",
824
+ "candidates",
825
+ "evaluations",
826
+ "selection",
827
+ "certificate",
828
+ "activation",
829
+ "lastLogicalTimeMs",
830
+ "lastEventDigest",
831
+ "events",
832
+ "stateDigest",
833
+ ], "role realignment state");
834
+ if (input.schemaVersion !== 1)
835
+ throw new TypeError("role_realignment_state_invalid");
836
+ for (const [label, value] of [
837
+ ["controllerId", input.controllerId],
838
+ ["implementationId", input.implementationId],
839
+ ["policyId", input.policyId],
840
+ ["originSessionId", input.originSessionId],
841
+ ["activeSessionId", input.activeSessionId],
842
+ ["originAgentId", input.originAgentId],
843
+ ["activeAgentId", input.activeAgentId],
844
+ ["tenantId", input.tenantId],
845
+ ["objectiveId", input.objectiveId],
846
+ ])
847
+ assertIdentifier(value, label);
848
+ assertSafeInteger(input.controllerVersion, "controllerVersion", 1);
849
+ assertSafeInteger(input.policyVersion, "policyVersion", 1);
850
+ assertSafeInteger(input.revision, "revision", 1);
851
+ assertSafeInteger(input.lastLogicalTimeMs, "lastLogicalTimeMs");
852
+ for (const [label, value] of [
853
+ ["policyDigest", input.policyDigest],
854
+ ["activeRoleAnchorDigest", input.activeRoleAnchorDigest],
855
+ ["lastEventDigest", input.lastEventDigest],
856
+ ["stateDigest", input.stateDigest],
857
+ ])
858
+ assertDigest(value, label);
859
+ assertOneOf(input.status, statuses, "status");
860
+ if (input.policyId !== policyRecord.policy.policyId ||
861
+ input.policyVersion !== policyRecord.policy.policyVersion ||
862
+ input.policyDigest !== policyRecord.policyDigest ||
863
+ (binding.controllerId !== undefined &&
864
+ input.controllerId !== binding.controllerId) ||
865
+ (binding.controllerVersion !== undefined &&
866
+ input.controllerVersion !== binding.controllerVersion) ||
867
+ (binding.implementationId !== undefined &&
868
+ input.implementationId !== binding.implementationId) ||
869
+ (binding.activeSessionId !== undefined &&
870
+ input.activeSessionId !== binding.activeSessionId))
871
+ throw new TypeError("role_realignment_state_binding_mismatch");
872
+ const request = validateRoleRealignmentRequestV1(input.request, policyRecord.policy);
873
+ if (request.sessionId !== input.originSessionId ||
874
+ request.agentId !== input.originAgentId ||
875
+ request.tenantId !== input.tenantId ||
876
+ request.objectiveId !== input.objectiveId)
877
+ throw new TypeError("role_realignment_state_binding_mismatch");
878
+ if (!Array.isArray(input.candidates) ||
879
+ !Array.isArray(input.evaluations) ||
880
+ !Array.isArray(input.events) ||
881
+ input.candidates.length > policyRecord.policy.limits.maximumCandidates ||
882
+ input.events.length > policyRecord.policy.limits.maximumRetainedEvents ||
883
+ input.revision < input.events.length ||
884
+ input.events.length === 0)
885
+ throw new TypeError("role_realignment_state_invalid");
886
+ sortedUnique(input.candidates.map(({ candidateDigest }) => candidateDigest), "candidate digests");
887
+ sortedUnique(input.evaluations.map(({ evaluationDigest }) => evaluationDigest), "evaluation digests");
888
+ const definitions = new Set();
889
+ const proposals = new Set();
890
+ for (const candidate of input.candidates) {
891
+ validateAdmittedRoleCandidateV1(candidate, request, policyRecord.policy);
892
+ if (definitions.has(candidate.proposal.definitionDigest) ||
893
+ proposals.has(candidate.proposal.proposalDigest))
894
+ throw new TypeError("role_realignment_state_invalid");
895
+ definitions.add(candidate.proposal.definitionDigest);
896
+ proposals.add(candidate.proposal.proposalDigest);
897
+ }
898
+ const evaluatorBindings = new Set();
899
+ for (const evaluation of input.evaluations) {
900
+ validateRoleCandidateEvaluationV1(evaluation, input, policyRecord.policy);
901
+ const key = `${evaluation.candidateDigest}\0${evaluation.evaluatorBindingDigest}`;
902
+ if (evaluatorBindings.has(key))
903
+ throw new TypeError("role_realignment_state_invalid");
904
+ evaluatorBindings.add(key);
905
+ }
906
+ for (const candidate of input.candidates) {
907
+ if (input.evaluations.filter(({ candidateDigest }) => candidateDigest === candidate.candidateDigest).length > policyRecord.policy.limits.maximumEvaluationsPerCandidate)
908
+ throw new TypeError("role_realignment_capacity_exhausted");
909
+ }
910
+ if (input.selection !== null)
911
+ validateRoleRealignmentSelectionV1(input.selection, input, policyRecord.policy);
912
+ if (input.certificate !== null)
913
+ validateRoleRealignmentCertificateV1(input.certificate, input, policyRecord.policy);
914
+ if (input.activation !== null)
915
+ validateRoleRealignmentActivationV1(input.activation, input, policyRecord.policy);
916
+ validateRoleRealignmentStatusShapeV1(input);
917
+ const firstSequence = input.revision - input.events.length + 1;
918
+ let previous = firstSequence === 1 ? null : input.events[0].previousEventDigest;
919
+ let previousTime = -1;
920
+ for (let index = 0; index < input.events.length; index += 1) {
921
+ const event = validateRoleRealignmentEventV1(input.events[index]);
922
+ if (event.eventSequence !== firstSequence + index ||
923
+ event.previousEventDigest !== previous ||
924
+ event.logicalTimeMs < previousTime)
925
+ throw new TypeError("role_realignment_event_chain_invalid");
926
+ previous = event.eventDigest;
927
+ previousTime = event.logicalTimeMs;
928
+ }
929
+ if (previous !== input.lastEventDigest ||
930
+ input.events[input.events.length - 1].logicalTimeMs !==
931
+ input.lastLogicalTimeMs)
932
+ throw new TypeError("role_realignment_event_chain_invalid");
933
+ const { stateDigest, ...body } = input;
934
+ if (digestRoleRealignmentJsonV1("state", body) !==
935
+ stateDigest)
936
+ throw new TypeError("role_realignment_state_digest_invalid");
937
+ ensureRoleRealignmentStateCapacityV1(input, policyRecord.policy);
938
+ return policyRecord.policy;
939
+ }
940
+ function validateThresholds(input) {
941
+ assertExactKeys(input, [
942
+ "minimumRoleFitBps",
943
+ "minimumMissionContributionBps",
944
+ "maximumUncertaintyBps",
945
+ "maximumTransitionRiskBps",
946
+ ], "role realignment thresholds");
947
+ for (const [label, value] of Object.entries(input)) {
948
+ assertSafeInteger(value, label);
949
+ if (value > ROLE_REALIGNMENT_BASIS_POINTS_V1)
950
+ throw new TypeError("role_realignment_threshold_invalid");
951
+ }
952
+ }
953
+ function validateWeights(input) {
954
+ assertExactKeys(input, [
955
+ "roleFitBps",
956
+ "missionContributionBps",
957
+ "uncertaintyPenaltyBps",
958
+ "transitionRiskPenaltyBps",
959
+ ], "role realignment scoring weights");
960
+ let total = 0;
961
+ for (const [label, value] of Object.entries(input)) {
962
+ assertSafeInteger(value, label);
963
+ if (value > ROLE_REALIGNMENT_BASIS_POINTS_V1)
964
+ throw new TypeError("role_realignment_weight_invalid");
965
+ total += value;
966
+ }
967
+ if (total !== ROLE_REALIGNMENT_BASIS_POINTS_V1)
968
+ throw new TypeError("role_realignment_weight_total_invalid");
969
+ }
970
+ function validateLimits(input) {
971
+ assertExactKeys(input, [
972
+ "maximumProposers",
973
+ "maximumCandidates",
974
+ "maximumEvaluationsPerCandidate",
975
+ "maximumReasonCodes",
976
+ "maximumEvidenceReferences",
977
+ "maximumCapabilities",
978
+ "maximumResourceClasses",
979
+ "maximumInstructions",
980
+ "maximumInstructionBytes",
981
+ "maximumConstraintsBytes",
982
+ "maximumRequestTtlMs",
983
+ "maximumEvaluationTtlMs",
984
+ "maximumCertificationTtlMs",
985
+ "maximumRetainedEvents",
986
+ "maximumStateBytes",
987
+ ], "role realignment limits");
988
+ for (const [label, value] of Object.entries(input))
989
+ assertSafeInteger(value, label, 1);
990
+ if (input.maximumCandidates > 256 ||
991
+ input.maximumProposers > 256 ||
992
+ input.maximumEvaluationsPerCandidate > 256 ||
993
+ input.maximumReasonCodes > 256 ||
994
+ input.maximumEvidenceReferences > 256 ||
995
+ input.maximumCapabilities > 1_024 ||
996
+ input.maximumResourceClasses > 1_024 ||
997
+ input.maximumInstructions > 128 ||
998
+ input.maximumInstructionBytes > 65_536 ||
999
+ input.maximumConstraintsBytes > 1_048_576 ||
1000
+ input.maximumRetainedEvents > 65_536 ||
1001
+ input.maximumStateBytes > 67_108_864)
1002
+ throw new TypeError("role_realignment_limit_invalid");
1003
+ }
1004
+ function normalizeAuthorityCeiling(input) {
1005
+ if (input.schemaVersion !== undefined && input.schemaVersion !== 1)
1006
+ throw new TypeError("role_authority_ceiling_invalid");
1007
+ assertDigest(input.mandateDigest, "mandateDigest");
1008
+ const capabilityKeys = normalizeIdentifierSet(input.capabilityKeys, "capabilityKeys");
1009
+ const resourceClasses = normalizeIdentifierSet(input.resourceClasses, "resourceClasses");
1010
+ assertSafeInteger(input.maximumActionBudgetUnits, "maximumActionBudgetUnits");
1011
+ assertSafeInteger(input.validUntilLogicalMs, "validUntilLogicalMs", 1);
1012
+ return deepFreeze({
1013
+ schemaVersion: 1,
1014
+ mandateDigest: input.mandateDigest,
1015
+ capabilityKeys,
1016
+ resourceClasses,
1017
+ maximumActionBudgetUnits: input.maximumActionBudgetUnits,
1018
+ validUntilLogicalMs: input.validUntilLogicalMs,
1019
+ });
1020
+ }
1021
+ function normalizeRoleDefinition(input) {
1022
+ if (input.schemaVersion !== 1)
1023
+ throw new TypeError("role_definition_invalid");
1024
+ for (const [label, value] of [
1025
+ ["catalogId", input.catalogId],
1026
+ ["definitionId", input.definitionId],
1027
+ ])
1028
+ assertIdentifier(value, label);
1029
+ assertSafeInteger(input.definitionRevision, "definitionRevision", 1);
1030
+ if (input.predecessorDefinitionDigest !== null)
1031
+ assertDigest(input.predecessorDefinitionDigest, "predecessorDefinitionDigest");
1032
+ if ((input.definitionRevision === 1 &&
1033
+ input.predecessorDefinitionDigest !== null) ||
1034
+ (input.definitionRevision > 1 && input.predecessorDefinitionDigest === null))
1035
+ throw new TypeError("role_definition_lineage_invalid");
1036
+ assertString(input.roleKey, "roleKey");
1037
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:/-]*$/u.test(input.roleKey))
1038
+ throw new TypeError("role_definition_role_key_invalid");
1039
+ if (!Array.isArray(input.instructions))
1040
+ throw new TypeError("role_definition_instructions_invalid");
1041
+ const instructions = input.instructions.map((value, index) => {
1042
+ assertString(value, `instructions[${index}]`);
1043
+ return value;
1044
+ });
1045
+ assertStrictJsonValue(input.constraints);
1046
+ if (input.constraints === null ||
1047
+ typeof input.constraints !== "object" ||
1048
+ Array.isArray(input.constraints))
1049
+ throw new TypeError("role_definition_constraints_invalid");
1050
+ const requiredCapabilityKeys = normalizeIdentifierSet(input.requiredCapabilityKeys, "requiredCapabilityKeys");
1051
+ const requiredResourceClasses = normalizeIdentifierSet(input.requiredResourceClasses, "requiredResourceClasses");
1052
+ assertSafeInteger(input.maximumActionBudgetUnits, "maximumActionBudgetUnits");
1053
+ assertSafeInteger(input.validFromLogicalMs, "validFromLogicalMs");
1054
+ assertSafeInteger(input.validUntilLogicalMs, "validUntilLogicalMs", 1);
1055
+ if (input.validUntilLogicalMs <= input.validFromLogicalMs)
1056
+ throw new TypeError("role_definition_lifetime_invalid");
1057
+ return deepFreeze({
1058
+ schemaVersion: 1,
1059
+ catalogId: input.catalogId,
1060
+ definitionId: input.definitionId,
1061
+ definitionRevision: input.definitionRevision,
1062
+ predecessorDefinitionDigest: input.predecessorDefinitionDigest,
1063
+ roleKey: input.roleKey,
1064
+ instructions,
1065
+ constraints: freezeClone(input.constraints),
1066
+ requiredCapabilityKeys,
1067
+ requiredResourceClasses,
1068
+ maximumActionBudgetUnits: input.maximumActionBudgetUnits,
1069
+ validFromLogicalMs: input.validFromLogicalMs,
1070
+ validUntilLogicalMs: input.validUntilLogicalMs,
1071
+ });
1072
+ }
1073
+ function normalizeProposal(input) {
1074
+ if (input.schemaVersion !== 1)
1075
+ throw new TypeError("role_candidate_proposal_invalid");
1076
+ for (const [label, value] of [
1077
+ ["proposalId", input.proposalId],
1078
+ ["proposerId", input.proposerId],
1079
+ ["definitionId", input.definitionId],
1080
+ ])
1081
+ assertIdentifier(value, label);
1082
+ assertSafeInteger(input.proposerVersion, "proposerVersion", 1);
1083
+ assertSafeInteger(input.definitionRevision, "definitionRevision", 1);
1084
+ for (const [label, value] of [
1085
+ ["requestDigest", input.requestDigest],
1086
+ ["proposerBindingDigest", input.proposerBindingDigest],
1087
+ ["definitionDigest", input.definitionDigest],
1088
+ ])
1089
+ assertDigest(value, label);
1090
+ const reasonCodes = normalizeIdentifierSet(input.reasonCodes, "reasonCodes");
1091
+ const evidenceReferenceIds = normalizeIdentifierSet(input.evidenceReferenceIds, "evidenceReferenceIds");
1092
+ assertSafeInteger(input.proposedAtLogicalMs, "proposedAtLogicalMs");
1093
+ assertSafeInteger(input.expiresAtLogicalMs, "expiresAtLogicalMs", 1);
1094
+ if (input.expiresAtLogicalMs <= input.proposedAtLogicalMs)
1095
+ throw new TypeError("role_candidate_proposal_lifetime_invalid");
1096
+ return deepFreeze({
1097
+ schemaVersion: 1,
1098
+ proposalId: input.proposalId,
1099
+ requestDigest: input.requestDigest,
1100
+ proposerId: input.proposerId,
1101
+ proposerVersion: input.proposerVersion,
1102
+ proposerBindingDigest: input.proposerBindingDigest,
1103
+ definitionId: input.definitionId,
1104
+ definitionRevision: input.definitionRevision,
1105
+ definitionDigest: input.definitionDigest,
1106
+ reasonCodes,
1107
+ evidenceReferenceIds,
1108
+ proposedAtLogicalMs: input.proposedAtLogicalMs,
1109
+ expiresAtLogicalMs: input.expiresAtLogicalMs,
1110
+ });
1111
+ }
1112
+ function normalizeEvaluation(input) {
1113
+ if (input.schemaVersion !== 1)
1114
+ throw new TypeError("role_candidate_evaluation_invalid");
1115
+ for (const [label, value] of [
1116
+ ["evaluationId", input.evaluationId],
1117
+ ["evaluatorId", input.evaluatorId],
1118
+ ])
1119
+ assertIdentifier(value, label);
1120
+ assertSafeInteger(input.evaluatorVersion, "evaluatorVersion", 1);
1121
+ for (const [label, value] of [
1122
+ ["requestDigest", input.requestDigest],
1123
+ ["candidateDigest", input.candidateDigest],
1124
+ ["definitionDigest", input.definitionDigest],
1125
+ ["evaluatorBindingDigest", input.evaluatorBindingDigest],
1126
+ ["eligibilityDecisionDigest", input.eligibilityDecisionDigest],
1127
+ ])
1128
+ assertDigest(value, label);
1129
+ if (typeof input.eligible !== "boolean")
1130
+ throw new TypeError("role_candidate_evaluation_invalid");
1131
+ for (const [label, value] of [
1132
+ ["roleFitBps", input.roleFitBps],
1133
+ ["missionContributionBps", input.missionContributionBps],
1134
+ ["uncertaintyBps", input.uncertaintyBps],
1135
+ ["transitionRiskBps", input.transitionRiskBps],
1136
+ ]) {
1137
+ assertSafeInteger(value, label);
1138
+ if (value > ROLE_REALIGNMENT_BASIS_POINTS_V1)
1139
+ throw new TypeError("role_candidate_evaluation_score_invalid");
1140
+ }
1141
+ const reasonCodes = normalizeIdentifierSet(input.reasonCodes, "reasonCodes");
1142
+ const evidenceReferenceIds = normalizeIdentifierSet(input.evidenceReferenceIds, "evidenceReferenceIds");
1143
+ assertSafeInteger(input.evaluatedAtLogicalMs, "evaluatedAtLogicalMs");
1144
+ assertSafeInteger(input.expiresAtLogicalMs, "expiresAtLogicalMs", 1);
1145
+ if (input.expiresAtLogicalMs <= input.evaluatedAtLogicalMs)
1146
+ throw new TypeError("role_candidate_evaluation_lifetime_invalid");
1147
+ return deepFreeze({
1148
+ schemaVersion: 1,
1149
+ evaluationId: input.evaluationId,
1150
+ requestDigest: input.requestDigest,
1151
+ candidateDigest: input.candidateDigest,
1152
+ definitionDigest: input.definitionDigest,
1153
+ evaluatorId: input.evaluatorId,
1154
+ evaluatorVersion: input.evaluatorVersion,
1155
+ evaluatorBindingDigest: input.evaluatorBindingDigest,
1156
+ eligibilityDecisionDigest: input.eligibilityDecisionDigest,
1157
+ eligible: input.eligible,
1158
+ roleFitBps: input.roleFitBps,
1159
+ missionContributionBps: input.missionContributionBps,
1160
+ uncertaintyBps: input.uncertaintyBps,
1161
+ transitionRiskBps: input.transitionRiskBps,
1162
+ reasonCodes,
1163
+ evidenceReferenceIds,
1164
+ evaluatedAtLogicalMs: input.evaluatedAtLogicalMs,
1165
+ expiresAtLogicalMs: input.expiresAtLogicalMs,
1166
+ });
1167
+ }
1168
+ function normalizeCertificate(input) {
1169
+ if (input.schemaVersion !== 1)
1170
+ throw new TypeError("role_realignment_certificate_invalid");
1171
+ for (const [label, value] of [
1172
+ ["certificateId", input.certificateId],
1173
+ ["certifierId", input.certifierId],
1174
+ ])
1175
+ assertIdentifier(value, label);
1176
+ assertOneOf(input.certificationKind, certificationKinds, "certificationKind");
1177
+ assertSafeInteger(input.certifierVersion, "certifierVersion", 1);
1178
+ for (const [label, value] of [
1179
+ ["certifierBindingDigest", input.certifierBindingDigest],
1180
+ ["requestDigest", input.requestDigest],
1181
+ ["selectionDigest", input.selectionDigest],
1182
+ ["selectedCandidateDigest", input.selectedCandidateDigest],
1183
+ ["selectedDefinitionDigest", input.selectedDefinitionDigest],
1184
+ ["authorityCeilingDigest", input.authorityCeilingDigest],
1185
+ ["sourceCertificateDigest", input.sourceCertificateDigest],
1186
+ ])
1187
+ assertDigest(value, label);
1188
+ const witnessIds = normalizeIdentifierSet(input.witnessIds, "witnessIds");
1189
+ if (input.certificationKind === "local_policy") {
1190
+ if (input.membershipEpoch !== null ||
1191
+ input.membershipConfigurationDigest !== null)
1192
+ throw new TypeError("role_realignment_certificate_membership_invalid");
1193
+ }
1194
+ else {
1195
+ assertSafeInteger(input.membershipEpoch, "membershipEpoch");
1196
+ assertDigest(input.membershipConfigurationDigest, "membershipConfigurationDigest");
1197
+ }
1198
+ assertSafeInteger(input.certifiedAtLogicalMs, "certifiedAtLogicalMs");
1199
+ assertSafeInteger(input.expiresAtLogicalMs, "expiresAtLogicalMs", 1);
1200
+ if (input.expiresAtLogicalMs <= input.certifiedAtLogicalMs)
1201
+ throw new TypeError("role_realignment_certificate_lifetime_invalid");
1202
+ return deepFreeze({
1203
+ schemaVersion: 1,
1204
+ certificateId: input.certificateId,
1205
+ certificationKind: input.certificationKind,
1206
+ certifierId: input.certifierId,
1207
+ certifierVersion: input.certifierVersion,
1208
+ certifierBindingDigest: input.certifierBindingDigest,
1209
+ requestDigest: input.requestDigest,
1210
+ selectionDigest: input.selectionDigest,
1211
+ selectedCandidateDigest: input.selectedCandidateDigest,
1212
+ selectedDefinitionDigest: input.selectedDefinitionDigest,
1213
+ authorityCeilingDigest: input.authorityCeilingDigest,
1214
+ witnessIds,
1215
+ membershipEpoch: input.membershipEpoch,
1216
+ membershipConfigurationDigest: input.membershipConfigurationDigest,
1217
+ sourceCertificateDigest: input.sourceCertificateDigest,
1218
+ certifiedAtLogicalMs: input.certifiedAtLogicalMs,
1219
+ expiresAtLogicalMs: input.expiresAtLogicalMs,
1220
+ });
1221
+ }
1222
+ function normalizeIdentifierSet(input, label) {
1223
+ if (!Array.isArray(input))
1224
+ throw new TypeError(`${label}_invalid`);
1225
+ const values = [...input];
1226
+ for (let index = 0; index < values.length; index += 1)
1227
+ assertIdentifier(values[index], `${label}[${index}]`);
1228
+ sortedUnique(values, label);
1229
+ return Object.freeze(values);
1230
+ }
1231
+ export function assertTrustedRoleDefinitionWithinAuthorityCeilingV1(definition, ceiling) {
1232
+ const capabilities = new Set(ceiling.capabilityKeys);
1233
+ const resources = new Set(ceiling.resourceClasses);
1234
+ if (definition.requiredCapabilityKeys.some((key) => !capabilities.has(key)) ||
1235
+ definition.requiredResourceClasses.some((key) => !resources.has(key)) ||
1236
+ definition.maximumActionBudgetUnits > ceiling.maximumActionBudgetUnits ||
1237
+ definition.validUntilLogicalMs > ceiling.validUntilLogicalMs)
1238
+ throw new TypeError("role_candidate_authority_widening_denied");
1239
+ }
1240
+ function aggregateRoleCandidateV1(candidate, evaluations, policy, logicalTimeMs) {
1241
+ if (candidate.proposal.expiresAtLogicalMs <= logicalTimeMs)
1242
+ return null;
1243
+ const eligible = evaluations
1244
+ .filter((evaluation) => evaluation.candidateDigest === candidate.candidateDigest &&
1245
+ evaluation.eligible &&
1246
+ evaluation.expiresAtLogicalMs > logicalTimeMs)
1247
+ .sort((left, right) => compareCodeUnits(left.evaluationDigest, right.evaluationDigest));
1248
+ if (eligible.length < policy.minimumIndependentEvaluations)
1249
+ return null;
1250
+ const meanRoleFitBps = integerMean(eligible.map(({ roleFitBps }) => roleFitBps));
1251
+ const meanMissionContributionBps = integerMean(eligible.map(({ missionContributionBps }) => missionContributionBps));
1252
+ const meanUncertaintyBps = integerMean(eligible.map(({ uncertaintyBps }) => uncertaintyBps));
1253
+ const meanTransitionRiskBps = integerMean(eligible.map(({ transitionRiskBps }) => transitionRiskBps));
1254
+ if (meanRoleFitBps < policy.thresholds.minimumRoleFitBps ||
1255
+ meanMissionContributionBps <
1256
+ policy.thresholds.minimumMissionContributionBps ||
1257
+ meanUncertaintyBps > policy.thresholds.maximumUncertaintyBps ||
1258
+ meanTransitionRiskBps > policy.thresholds.maximumTransitionRiskBps)
1259
+ return null;
1260
+ const weights = policy.scoringWeights;
1261
+ const numerator = meanRoleFitBps * weights.roleFitBps +
1262
+ meanMissionContributionBps * weights.missionContributionBps -
1263
+ meanUncertaintyBps * weights.uncertaintyPenaltyBps -
1264
+ meanTransitionRiskBps * weights.transitionRiskPenaltyBps;
1265
+ return deepFreeze({
1266
+ schemaVersion: 1,
1267
+ candidateId: candidate.candidateId,
1268
+ candidateDigest: candidate.candidateDigest,
1269
+ definitionDigest: candidate.proposal.definitionDigest,
1270
+ eligibleEvaluationDigests: eligible.map(({ evaluationDigest }) => evaluationDigest),
1271
+ meanRoleFitBps,
1272
+ meanMissionContributionBps,
1273
+ meanUncertaintyBps,
1274
+ meanTransitionRiskBps,
1275
+ aggregateScore: Math.floor(numerator / ROLE_REALIGNMENT_BASIS_POINTS_V1),
1276
+ });
1277
+ }
1278
+ function integerMean(values) {
1279
+ if (!values.length)
1280
+ throw new TypeError("role_realignment_mean_empty");
1281
+ return Math.floor(values.reduce((sum, value) => sum + value, 0) / values.length);
1282
+ }
1283
+ function validateAdmittedRoleCandidateV1(input, request, policy) {
1284
+ assertExactKeys(input, [
1285
+ "schemaVersion",
1286
+ "candidateId",
1287
+ "requestDigest",
1288
+ "proposal",
1289
+ "proposerEligibilityDecisionDigest",
1290
+ "catalogId",
1291
+ "admittedAtLogicalMs",
1292
+ "candidateDigest",
1293
+ ], "admitted role candidate");
1294
+ if (input.schemaVersion !== 1)
1295
+ throw new TypeError("role_candidate_invalid");
1296
+ assertIdentifier(input.candidateId, "candidateId");
1297
+ assertDigest(input.requestDigest, "requestDigest");
1298
+ assertDigest(input.proposerEligibilityDecisionDigest, "proposerEligibilityDecisionDigest");
1299
+ assertIdentifier(input.catalogId, "catalogId");
1300
+ assertSafeInteger(input.admittedAtLogicalMs, "admittedAtLogicalMs");
1301
+ assertDigest(input.candidateDigest, "candidateDigest");
1302
+ const proposal = validateRoleCandidateProposalV1(input.proposal, request, policy);
1303
+ const { candidateDigest, ...body } = input;
1304
+ if (input.requestDigest !== request.requestDigest ||
1305
+ input.admittedAtLogicalMs < proposal.proposedAtLogicalMs ||
1306
+ input.admittedAtLogicalMs >= proposal.expiresAtLogicalMs ||
1307
+ digestRoleRealignmentJsonV1("candidate", body) !==
1308
+ candidateDigest)
1309
+ throw new TypeError("role_candidate_invalid");
1310
+ }
1311
+ function validateRoleRealignmentSelectionV1(input, state, policy) {
1312
+ assertExactKeys(input, [
1313
+ "schemaVersion",
1314
+ "selectionId",
1315
+ "requestDigest",
1316
+ "stateRevision",
1317
+ "aggregates",
1318
+ "selectedCandidateId",
1319
+ "selectedCandidateDigest",
1320
+ "selectedDefinitionDigest",
1321
+ "selectedAtLogicalMs",
1322
+ "selectionDigest",
1323
+ ], "role realignment selection");
1324
+ if (input.schemaVersion !== 1 || !Array.isArray(input.aggregates))
1325
+ throw new TypeError("role_realignment_selection_invalid");
1326
+ assertIdentifier(input.selectionId, "selectionId");
1327
+ assertIdentifier(input.selectedCandidateId, "selectedCandidateId");
1328
+ assertSafeInteger(input.stateRevision, "stateRevision", 1);
1329
+ assertSafeInteger(input.selectedAtLogicalMs, "selectedAtLogicalMs");
1330
+ for (const [label, value] of [
1331
+ ["requestDigest", input.requestDigest],
1332
+ ["selectedCandidateDigest", input.selectedCandidateDigest],
1333
+ ["selectedDefinitionDigest", input.selectedDefinitionDigest],
1334
+ ["selectionDigest", input.selectionDigest],
1335
+ ])
1336
+ assertDigest(value, label);
1337
+ sortedUnique(input.aggregates.map(({ candidateDigest }) => candidateDigest), "aggregate candidate digests");
1338
+ for (const aggregate of input.aggregates)
1339
+ validateRoleCandidateAggregateV1(aggregate);
1340
+ const winner = input.aggregates.find(({ candidateDigest }) => candidateDigest === input.selectedCandidateDigest);
1341
+ const candidate = state.candidates.find(({ candidateDigest }) => candidateDigest === input.selectedCandidateDigest);
1342
+ const expectedAggregates = state.candidates
1343
+ .map((item) => aggregateRoleCandidateV1(item, state.evaluations, policy, input.selectedAtLogicalMs))
1344
+ .filter((item) => item !== null)
1345
+ .sort((left, right) => compareCodeUnits(left.candidateDigest, right.candidateDigest));
1346
+ const expectedWinner = [...expectedAggregates].sort((left, right) => right.aggregateScore - left.aggregateScore ||
1347
+ compareCodeUnits(left.definitionDigest, right.definitionDigest) ||
1348
+ compareCodeUnits(left.candidateDigest, right.candidateDigest))[0];
1349
+ const retainedSelectionEvent = state.events.find((event) => event.eventType === "candidate_selected" &&
1350
+ event.inputDigest === input.selectionDigest);
1351
+ const { selectionDigest, ...body } = input;
1352
+ if (input.requestDigest !== state.request.requestDigest ||
1353
+ input.selectedAtLogicalMs >= state.request.expiresAtLogicalMs ||
1354
+ !winner ||
1355
+ !candidate ||
1356
+ !expectedWinner ||
1357
+ canonicalizeControlJsonV1(input.aggregates) !==
1358
+ canonicalizeControlJsonV1(expectedAggregates) ||
1359
+ expectedWinner.candidateDigest !== input.selectedCandidateDigest ||
1360
+ winner.candidateId !== input.selectedCandidateId ||
1361
+ winner.definitionDigest !== input.selectedDefinitionDigest ||
1362
+ candidate.proposal.definitionDigest !== input.selectedDefinitionDigest ||
1363
+ (retainedSelectionEvent !== undefined &&
1364
+ input.stateRevision !== retainedSelectionEvent.eventSequence - 1) ||
1365
+ digestRoleRealignmentJsonV1("selection", body) !==
1366
+ selectionDigest)
1367
+ throw new TypeError("role_realignment_selection_invalid");
1368
+ }
1369
+ function validateRoleCandidateAggregateV1(input) {
1370
+ assertExactKeys(input, [
1371
+ "schemaVersion",
1372
+ "candidateId",
1373
+ "candidateDigest",
1374
+ "definitionDigest",
1375
+ "eligibleEvaluationDigests",
1376
+ "meanRoleFitBps",
1377
+ "meanMissionContributionBps",
1378
+ "meanUncertaintyBps",
1379
+ "meanTransitionRiskBps",
1380
+ "aggregateScore",
1381
+ ], "role candidate aggregate");
1382
+ if (input.schemaVersion !== 1)
1383
+ throw new TypeError("role_candidate_aggregate_invalid");
1384
+ assertIdentifier(input.candidateId, "candidateId");
1385
+ assertDigest(input.candidateDigest, "candidateDigest");
1386
+ assertDigest(input.definitionDigest, "definitionDigest");
1387
+ if (!Array.isArray(input.eligibleEvaluationDigests))
1388
+ throw new TypeError("role_candidate_aggregate_invalid");
1389
+ for (const digest of input.eligibleEvaluationDigests)
1390
+ assertDigest(digest, "eligibleEvaluationDigest");
1391
+ sortedUnique(input.eligibleEvaluationDigests, "eligible evaluation digests");
1392
+ for (const [label, value] of [
1393
+ ["meanRoleFitBps", input.meanRoleFitBps],
1394
+ ["meanMissionContributionBps", input.meanMissionContributionBps],
1395
+ ["meanUncertaintyBps", input.meanUncertaintyBps],
1396
+ ["meanTransitionRiskBps", input.meanTransitionRiskBps],
1397
+ ]) {
1398
+ assertSafeInteger(value, label);
1399
+ if (value > ROLE_REALIGNMENT_BASIS_POINTS_V1)
1400
+ throw new TypeError("role_candidate_aggregate_invalid");
1401
+ }
1402
+ if (!Number.isSafeInteger(input.aggregateScore))
1403
+ throw new TypeError("role_candidate_aggregate_invalid");
1404
+ }
1405
+ function validateRoleRealignmentActivationV1(input, state, policy) {
1406
+ assertExactKeys(input, [
1407
+ "schemaVersion",
1408
+ "activationId",
1409
+ "requestDigest",
1410
+ "selectionDigest",
1411
+ "certificateDigest",
1412
+ "definition",
1413
+ "roleBinding",
1414
+ "roleBindingDigest",
1415
+ "startedAtLogicalMs",
1416
+ "completedAtLogicalMs",
1417
+ "runtimeSessionRevision",
1418
+ "alignmentStateRevision",
1419
+ "alignmentRoleAnchorDigest",
1420
+ "activationDigest",
1421
+ ], "role realignment activation");
1422
+ if (input.schemaVersion !== 1 || !state.selection || !state.certificate)
1423
+ throw new TypeError("role_realignment_activation_invalid");
1424
+ assertIdentifier(input.activationId, "activationId");
1425
+ for (const [label, value] of [
1426
+ ["requestDigest", input.requestDigest],
1427
+ ["selectionDigest", input.selectionDigest],
1428
+ ["certificateDigest", input.certificateDigest],
1429
+ ["roleBindingDigest", input.roleBindingDigest],
1430
+ ["activationDigest", input.activationDigest],
1431
+ ])
1432
+ assertDigest(value, label);
1433
+ const definition = validateTrustedRoleDefinitionV1(input.definition, policy);
1434
+ assertTrustedRoleDefinitionWithinAuthorityCeilingV1(definition, state.request.authorityCeiling);
1435
+ const roleBinding = normalizeRoleBindingV1(input.roleBinding);
1436
+ assertSafeInteger(input.startedAtLogicalMs, "startedAtLogicalMs");
1437
+ const complete = input.completedAtLogicalMs !== null;
1438
+ if (complete) {
1439
+ assertSafeInteger(input.completedAtLogicalMs, "completedAtLogicalMs");
1440
+ assertSafeInteger(input.runtimeSessionRevision, "runtimeSessionRevision", 1);
1441
+ assertSafeInteger(input.alignmentStateRevision, "alignmentStateRevision", 1);
1442
+ assertDigest(input.alignmentRoleAnchorDigest, "alignmentRoleAnchorDigest");
1443
+ }
1444
+ else if (input.runtimeSessionRevision !== null ||
1445
+ input.alignmentStateRevision !== null ||
1446
+ input.alignmentRoleAnchorDigest !== null) {
1447
+ throw new TypeError("role_realignment_activation_invalid");
1448
+ }
1449
+ const { activationDigest, ...body } = input;
1450
+ const selectedCandidate = state.candidates.find(({ candidateDigest }) => candidateDigest === state.selection.selectedCandidateDigest);
1451
+ const expectedValidFrom = selectedCandidate
1452
+ ? Math.max(input.startedAtLogicalMs, definition.validFromLogicalMs)
1453
+ : -1;
1454
+ const expectedValidUntil = selectedCandidate
1455
+ ? Math.min(definition.validUntilLogicalMs, state.request.expiresAtLogicalMs, state.request.authorityCeiling.validUntilLogicalMs)
1456
+ : -1;
1457
+ if (input.requestDigest !== state.request.requestDigest ||
1458
+ input.selectionDigest !== state.selection.selectionDigest ||
1459
+ input.certificateDigest !== state.certificate.certificateDigest ||
1460
+ !selectedCandidate ||
1461
+ selectedCandidate.catalogId !== definition.catalogId ||
1462
+ selectedCandidate.proposal.definitionId !== definition.definitionId ||
1463
+ selectedCandidate.proposal.definitionRevision !==
1464
+ definition.definitionRevision ||
1465
+ selectedCandidate.proposal.definitionDigest !==
1466
+ definition.definitionDigest ||
1467
+ roleBinding.roleBindingId !==
1468
+ `role-${definition.definitionDigest.slice(7, 39)}` ||
1469
+ roleBinding.objectiveId !== state.objectiveId ||
1470
+ roleBinding.roleRevision !== state.request.currentRoleRevision + 1 ||
1471
+ roleBinding.predecessorRoleBindingId !==
1472
+ state.request.currentRoleBindingId ||
1473
+ roleBinding.roleKey !== definition.roleKey ||
1474
+ canonicalizeControlJsonV1(roleBinding.instructions) !==
1475
+ canonicalizeControlJsonV1(definition.instructions) ||
1476
+ canonicalizeControlJsonV1(roleBinding.constraints) !==
1477
+ canonicalizeControlJsonV1(definition.constraints) ||
1478
+ roleBinding.validFromLogicalMs !== expectedValidFrom ||
1479
+ roleBinding.validUntilLogicalMs !== expectedValidUntil ||
1480
+ digestRoleRealignmentJsonV1("role_binding", roleBinding) !== input.roleBindingDigest ||
1481
+ digestRoleRealignmentJsonV1("activation", body) !==
1482
+ activationDigest)
1483
+ throw new TypeError("role_realignment_activation_invalid");
1484
+ }
1485
+ function validateRoleRealignmentEventV1(input) {
1486
+ assertExactKeys(input, [
1487
+ "schemaVersion",
1488
+ "eventSequence",
1489
+ "eventType",
1490
+ "inputDigest",
1491
+ "reasonCode",
1492
+ "logicalTimeMs",
1493
+ "previousEventDigest",
1494
+ "eventDigest",
1495
+ ], "role realignment event");
1496
+ if (input.schemaVersion !== 1)
1497
+ throw new TypeError("role_realignment_event_invalid");
1498
+ assertSafeInteger(input.eventSequence, "eventSequence", 1);
1499
+ assertOneOf(input.eventType, eventTypes, "eventType");
1500
+ assertDigest(input.inputDigest, "inputDigest");
1501
+ assertIdentifier(input.reasonCode, "reasonCode");
1502
+ assertSafeInteger(input.logicalTimeMs, "logicalTimeMs");
1503
+ if (input.previousEventDigest !== null)
1504
+ assertDigest(input.previousEventDigest, "previousEventDigest");
1505
+ assertDigest(input.eventDigest, "eventDigest");
1506
+ const { eventDigest, ...body } = input;
1507
+ if (digestRoleRealignmentJsonV1("event", body) !==
1508
+ eventDigest)
1509
+ throw new TypeError("role_realignment_event_invalid");
1510
+ return freezeClone(input);
1511
+ }
1512
+ function validateRoleRealignmentStatusShapeV1(state) {
1513
+ const hasSelection = state.selection !== null;
1514
+ const hasCertificate = state.certificate !== null;
1515
+ const hasActivation = state.activation !== null;
1516
+ if (((state.status === "requested" || state.status === "collecting") &&
1517
+ (hasSelection || hasCertificate || hasActivation)) ||
1518
+ (state.status === "selected" &&
1519
+ (!hasSelection || hasCertificate || hasActivation)) ||
1520
+ (state.status === "certified" &&
1521
+ (!hasSelection || !hasCertificate || hasActivation)) ||
1522
+ ((state.status === "activating" || state.status === "activated") &&
1523
+ (!hasSelection || !hasCertificate || !hasActivation)) ||
1524
+ (state.status === "activating" &&
1525
+ state.activation?.completedAtLogicalMs !== null) ||
1526
+ (state.status === "activated" &&
1527
+ state.activation?.completedAtLogicalMs === null))
1528
+ throw new TypeError("role_realignment_state_status_invalid");
1529
+ }
1530
+ function createRoleRealignmentEventV1(input) {
1531
+ assertSafeInteger(input.eventSequence, "eventSequence", 1);
1532
+ assertOneOf(input.eventType, eventTypes, "eventType");
1533
+ assertDigest(input.inputDigest, "inputDigest");
1534
+ assertIdentifier(input.reasonCode, "reasonCode");
1535
+ assertSafeInteger(input.logicalTimeMs, "logicalTimeMs");
1536
+ if (input.previousEventDigest !== null)
1537
+ assertDigest(input.previousEventDigest, "previousEventDigest");
1538
+ const body = { schemaVersion: 1, ...input };
1539
+ return deepFreeze({
1540
+ ...body,
1541
+ eventDigest: digestRoleRealignmentJsonV1("event", body),
1542
+ });
1543
+ }
1544
+ function transitionRoleRealignmentStateV1(input) {
1545
+ if (!input.permitExpiredTime)
1546
+ requireRoleRealignmentTimeV1(input.state, input.logicalTimeMs);
1547
+ else {
1548
+ assertSafeInteger(input.logicalTimeMs, "logicalTimeMs");
1549
+ if (input.logicalTimeMs < input.state.lastLogicalTimeMs)
1550
+ throw new TypeError("role_realignment_clock_rollback");
1551
+ }
1552
+ const event = createRoleRealignmentEventV1({
1553
+ eventSequence: input.state.revision + 1,
1554
+ eventType: input.eventType,
1555
+ inputDigest: input.inputDigest,
1556
+ reasonCode: input.reasonCode,
1557
+ logicalTimeMs: input.logicalTimeMs,
1558
+ previousEventDigest: input.state.lastEventDigest,
1559
+ });
1560
+ const next = withRoleRealignmentStateDigestV1({
1561
+ ...withoutRoleRealignmentStateDigestV1(input.state),
1562
+ ...input.patch,
1563
+ revision: input.state.revision + 1,
1564
+ lastLogicalTimeMs: input.logicalTimeMs,
1565
+ lastEventDigest: event.eventDigest,
1566
+ events: retainRoleRealignmentEventsV1(input.state.events, event, input.policy),
1567
+ });
1568
+ ensureRoleRealignmentStateCapacityV1(next, input.policy);
1569
+ return deepFreeze({ state: next, event });
1570
+ }
1571
+ function retainRoleRealignmentEventsV1(events, event, policy) {
1572
+ return Object.freeze([...events, event].slice(-policy.limits.maximumRetainedEvents));
1573
+ }
1574
+ function withRoleRealignmentStateDigestV1(input) {
1575
+ return deepFreeze({
1576
+ ...input,
1577
+ stateDigest: digestRoleRealignmentJsonV1("state", input),
1578
+ });
1579
+ }
1580
+ function withoutRoleRealignmentStateDigestV1(input) {
1581
+ const { stateDigest: _ignored, ...body } = input;
1582
+ return body;
1583
+ }
1584
+ function ensureRoleRealignmentStateCapacityV1(state, policy) {
1585
+ if (utf8ByteLength(canonicalizeControlJsonV1(state)) >
1586
+ policy.limits.maximumStateBytes)
1587
+ throw new TypeError("role_realignment_capacity_exhausted");
1588
+ }
1589
+ function requireRoleRealignmentRevisionV1(state, expectedRevision) {
1590
+ assertSafeInteger(expectedRevision, "expectedRevision", 1);
1591
+ if (state.revision !== expectedRevision)
1592
+ throw new TypeError("role_realignment_revision_conflict");
1593
+ }
1594
+ function requireRoleRealignmentOpenV1(state, allowed) {
1595
+ if (!allowed.includes(state.status))
1596
+ throw new TypeError(`role_realignment_${state.status}`);
1597
+ }
1598
+ function requireRoleRealignmentTimeV1(state, logicalTimeMs, permitExpiry = false) {
1599
+ assertSafeInteger(logicalTimeMs, "logicalTimeMs");
1600
+ if (logicalTimeMs < state.lastLogicalTimeMs)
1601
+ throw new TypeError("role_realignment_clock_rollback");
1602
+ if (!permitExpiry && logicalTimeMs >= state.request.expiresAtLogicalMs)
1603
+ throw new TypeError("role_realignment_request_expired");
1604
+ }
1605
+ function freezeClone(input) {
1606
+ assertStrictJsonValue(input);
1607
+ return deepFreeze(JSON.parse(JSON.stringify(input)));
1608
+ }
1609
+ //# sourceMappingURL=role-realignment.js.map