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

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,778 @@
1
+ import { createAssessorEnsembleRequestV1, createAssessorEnsembleVerdictV1, } from "./assessor-ensemble-validation.js";
2
+ import { digestInferenceInterventionV1 } from "./intervention-validation.js";
3
+ import { sha256Hex } from "./sha256.js";
4
+ import { SEMANTIC_CONTROL_DIMENSIONS_V1, } from "./semantic-alignment-contracts.js";
5
+ import { InMemorySemanticControlStateStoreV1, createSemanticControlStateV1, validateSemanticControlStateV1, } from "./semantic-alignment-memory.js";
6
+ import { createSemanticAggregateAssessmentV1, createSemanticActionAuthorizationClaimsV1, digestSemanticControlV1, digestSemanticOperationPayloadV1, dimensionMetricKey, validateSemanticAssessorAssessmentV1, validateSemanticAssessorDescriptorV1, validateSemanticControlBindingV1, validateSemanticControlPolicyV1, validateSemanticControlRequestV1, validateSemanticActionAuthorizationV1, validateSemanticActionEffectReceiptV1, } from "./semantic-alignment-validation.js";
7
+ import { assertDigest, assertIdentifier, assertSafeInteger, deepFreeze, } from "./validation.js";
8
+ const requiredSemanticDimensions = [
9
+ "role_coherence",
10
+ "mission_alignment",
11
+ "context_conflict",
12
+ "uncertainty",
13
+ ];
14
+ const beneficialDimensions = new Set([
15
+ "role_coherence",
16
+ "mission_alignment",
17
+ "course_action_diversity",
18
+ "course_action_novelty",
19
+ ]);
20
+ const encoder = new TextEncoder();
21
+ export class SemanticAlignmentAgilityRuntimeV1 {
22
+ options;
23
+ store;
24
+ anchor;
25
+ stateKey;
26
+ assessorSetDigest;
27
+ constructor(options) {
28
+ this.options = options;
29
+ validateSemanticControlBindingV1(options.binding);
30
+ validateSemanticControlPolicyV1(options.policy);
31
+ if (!options.assessors.length || options.assessors.length > options.policy.limits.maximumAssessors)
32
+ throw new RangeError("semantic_assessor_count_invalid");
33
+ const ids = new Set();
34
+ for (const assessor of options.assessors) {
35
+ validateSemanticAssessorDescriptorV1(assessor.descriptor);
36
+ if (ids.has(assessor.descriptor.assessorId))
37
+ throw new TypeError("semantic_assessor_id_duplicate");
38
+ ids.add(assessor.descriptor.assessorId);
39
+ }
40
+ for (const id of options.policy.enforcingAssessorIds) {
41
+ const descriptor = options.assessors.find((item) => item.descriptor.assessorId === id)?.descriptor;
42
+ if (!descriptor)
43
+ throw new TypeError("semantic_enforcing_assessor_missing");
44
+ if (descriptor.basis === "reference_digest_heuristic")
45
+ throw new TypeError("digest_heuristic_cannot_enforce_constraints");
46
+ }
47
+ for (const dimension of requiredSemanticDimensions) {
48
+ const groups = new Set(options.assessors
49
+ .filter((assessor) => assessor.descriptor.supportedDimensions.includes(dimension))
50
+ .map((assessor) => assessor.descriptor.independenceGroup));
51
+ if (groups.size < options.policy.minimumGroupsPerDimension)
52
+ throw new TypeError(`semantic_dimension_coverage_unavailable:${dimension}`);
53
+ }
54
+ if (options.ensemble) {
55
+ assertDigest(options.ensemble.bindingDigest, "ensemble.bindingDigest");
56
+ assertDigest(options.ensemble.policyDigest, "ensemble.policyDigest");
57
+ if (typeof options.ensemble.verifyVerdict !== "function")
58
+ throw new TypeError("semantic_ensemble_verifier_required");
59
+ }
60
+ if (options.intervention) {
61
+ assertDigest(options.intervention.bindingDigest, "intervention.bindingDigest");
62
+ assertDigest(options.intervention.policyDigest, "intervention.policyDigest");
63
+ if (typeof options.intervention.verifyOperationGate !== "function")
64
+ throw new TypeError("semantic_intervention_verifier_required");
65
+ }
66
+ if (options.actionAuthorization) {
67
+ assertDigest(options.actionAuthorization.effectConsumerDigest, "actionAuthorization.effectConsumerDigest");
68
+ assertIdentifier(options.actionAuthorization.sinkId, "actionAuthorization.sinkId");
69
+ assertDigest(options.actionAuthorization.sinkKeyDigest, "actionAuthorization.sinkKeyDigest");
70
+ assertIdentifier(options.actionAuthorization.authority.issuerId, "actionAuthorization.issuerId");
71
+ assertDigest(options.actionAuthorization.authority.issuerKeyDigest, "actionAuthorization.issuerKeyDigest");
72
+ if (typeof options.actionAuthorization.authority.issue !== "function" ||
73
+ typeof options.actionAuthorization.authority.lookupAndVerify !== "function")
74
+ throw new TypeError("semantic_action_authorization_authority_invalid");
75
+ }
76
+ this.assessorSetDigest = digestSemanticControlV1("assessor-set", {
77
+ assessors: options.assessors
78
+ .map((item) => item.descriptor.descriptorDigest)
79
+ .sort(),
80
+ ensemble: options.ensemble
81
+ ? {
82
+ bindingDigest: options.ensemble.bindingDigest,
83
+ policyDigest: options.ensemble.policyDigest,
84
+ }
85
+ : null,
86
+ intervention: options.intervention
87
+ ? {
88
+ bindingDigest: options.intervention.bindingDigest,
89
+ policyDigest: options.intervention.policyDigest,
90
+ }
91
+ : null,
92
+ actionAuthorization: options.actionAuthorization
93
+ ? {
94
+ effectConsumerDigest: options.actionAuthorization.effectConsumerDigest,
95
+ sinkId: options.actionAuthorization.sinkId,
96
+ sinkKeyDigest: options.actionAuthorization.sinkKeyDigest,
97
+ issuerId: options.actionAuthorization.authority.issuerId,
98
+ issuerKeyDigest: options.actionAuthorization.authority.issuerKeyDigest,
99
+ }
100
+ : null,
101
+ });
102
+ this.stateKey = `semantic-alignment:${options.binding.bindingId}`;
103
+ this.store = options.store ?? new InMemorySemanticControlStateStoreV1();
104
+ this.anchor =
105
+ options.monotonicAnchor ??
106
+ this.store;
107
+ if (typeof this.anchor.readAnchor !== "function")
108
+ throw new TypeError("semantic_external_monotonic_anchor_required");
109
+ }
110
+ async getState() {
111
+ const state = await this.store.load(this.stateKey);
112
+ if (state)
113
+ await this.validateState(state);
114
+ else if (await this.anchor.readAnchor(this.stateKey))
115
+ throw new TypeError("semantic_state_missing_below_anchor");
116
+ return state;
117
+ }
118
+ async preStep(input) {
119
+ this.requireCheckpoint(input, "pre_step");
120
+ return this.evaluate(input);
121
+ }
122
+ async postOutput(input) {
123
+ this.requireCheckpoint(input, "post_output");
124
+ return this.evaluate(input);
125
+ }
126
+ async preAction(input) {
127
+ this.requireCheckpoint(input, "pre_action");
128
+ return this.evaluate(input);
129
+ }
130
+ async runStep(input, run) {
131
+ const decision = await this.preStep(input);
132
+ return deepFreeze({ decision, value: decision.proceed ? await run() : null });
133
+ }
134
+ async releaseOutput(input, release) {
135
+ const decision = await this.postOutput(input);
136
+ return deepFreeze({ decision, value: decision.proceed ? await release() : null });
137
+ }
138
+ async authorizeAction(input) {
139
+ const decision = await this.preAction(input);
140
+ if (!decision.proceed)
141
+ return deepFreeze({ decision, authorization: null });
142
+ const boundary = this.options.actionAuthorization;
143
+ if (!boundary)
144
+ throw new TypeError("semantic_action_authorization_boundary_required");
145
+ const request = validateSemanticControlRequestV1(input.request);
146
+ if (request.actionPayloadDigest === null)
147
+ throw new TypeError("semantic_action_payload_digest_required");
148
+ const committed = await this.getState();
149
+ if (!committed ||
150
+ committed.revision < decision.committedStateRevision ||
151
+ ![
152
+ committed.lastDecision?.decisionDigest,
153
+ ...committed.recentDecisions.map((item) => item.decisionDigest),
154
+ ].includes(decision.decisionDigest))
155
+ throw new TypeError("semantic_action_decision_not_committed");
156
+ const maximumLogicalTimeMs = this.options.policy.limits.maximumLogicalTimeMs;
157
+ const ttlMs = this.options.policy.limits.actionAuthorizationTtlMs;
158
+ const validUntilLogicalTimeMs = ttlMs > maximumLogicalTimeMs - request.logicalTimeMs
159
+ ? maximumLogicalTimeMs
160
+ : request.logicalTimeMs + ttlMs;
161
+ const claims = createSemanticActionAuthorizationClaimsV1({
162
+ schemaVersion: 1,
163
+ authorizationId: request.requestId,
164
+ requestDigest: request.requestDigest,
165
+ decisionDigest: decision.decisionDigest,
166
+ bindingDigest: request.bindingDigest,
167
+ authorityDigest: request.authorityDigest,
168
+ policyDigest: this.options.policy.policyDigest,
169
+ assessorSetDigest: this.assessorSetDigest,
170
+ effectConsumerDigest: boundary.effectConsumerDigest,
171
+ sinkId: boundary.sinkId,
172
+ sinkKeyDigest: boundary.sinkKeyDigest,
173
+ targetDigest: request.targetDigest,
174
+ materialDigest: request.materialDigest,
175
+ actionPayloadDigest: request.actionPayloadDigest,
176
+ sequence: request.sequence,
177
+ committedStateRevision: decision.committedStateRevision,
178
+ validFromLogicalTimeMs: request.logicalTimeMs,
179
+ validUntilLogicalTimeMs,
180
+ });
181
+ const issued = validateSemanticActionAuthorizationV1(await boundary.authority.issue(claims), boundary.authority);
182
+ if (issued.claims.claimsDigest !== claims.claimsDigest)
183
+ throw new TypeError("semantic_action_authorization_claims_mismatch");
184
+ const authorization = await this.verifyActionAuthorization({
185
+ authorizationId: claims.authorizationId,
186
+ authorizationDigest: issued.authorizationDigest,
187
+ expectedTargetDigest: claims.targetDigest,
188
+ expectedActionPayloadDigest: claims.actionPayloadDigest,
189
+ currentLogicalTimeMs: request.logicalTimeMs,
190
+ });
191
+ return deepFreeze({ decision, authorization });
192
+ }
193
+ async verifyActionAuthorization(input) {
194
+ const boundary = this.options.actionAuthorization;
195
+ if (!boundary)
196
+ throw new TypeError("semantic_action_authorization_boundary_required");
197
+ assertIdentifier(input.authorizationId, "authorizationId");
198
+ if (input.authorizationDigest !== undefined)
199
+ assertDigest(input.authorizationDigest, "authorizationDigest");
200
+ assertDigest(input.expectedTargetDigest, "expectedTargetDigest");
201
+ assertDigest(input.expectedActionPayloadDigest, "expectedActionPayloadDigest");
202
+ assertSafeInteger(input.currentLogicalTimeMs, "currentLogicalTimeMs");
203
+ if (input.currentLogicalTimeMs > this.options.policy.limits.maximumLogicalTimeMs)
204
+ throw new RangeError("semantic_action_authorization_logical_time_exceeded");
205
+ const current = await this.getState();
206
+ if (!current)
207
+ throw new TypeError("semantic_action_authorization_state_missing");
208
+ if (input.currentLogicalTimeMs < current.logicalTimeHighWaterMs)
209
+ throw new RangeError("semantic_action_authorization_time_below_high_water");
210
+ const verified = await boundary.authority.lookupAndVerify({
211
+ authorizationId: input.authorizationId,
212
+ ...(input.authorizationDigest === undefined
213
+ ? {}
214
+ : { authorizationDigest: input.authorizationDigest }),
215
+ effectConsumerDigest: boundary.effectConsumerDigest,
216
+ sinkId: boundary.sinkId,
217
+ sinkKeyDigest: boundary.sinkKeyDigest,
218
+ currentLogicalTimeMs: input.currentLogicalTimeMs,
219
+ currentStateRevision: current.revision,
220
+ });
221
+ if (!verified)
222
+ throw new TypeError("semantic_action_authorization_unverified");
223
+ const authorization = validateSemanticActionAuthorizationV1(verified, boundary.authority);
224
+ const claims = authorization.claims;
225
+ const retained = current.recentDecisions.find((record) => record.requestDigest === claims.requestDigest &&
226
+ record.decisionDigest === claims.decisionDigest &&
227
+ record.sequence === claims.sequence &&
228
+ record.checkpoint === "pre_action" &&
229
+ record.disposition === "allow");
230
+ if (claims.authorizationId !== input.authorizationId ||
231
+ claims.bindingDigest !== this.options.binding.bindingDigest ||
232
+ claims.authorityDigest !== this.options.binding.authorityDigest ||
233
+ claims.policyDigest !== this.options.policy.policyDigest ||
234
+ claims.assessorSetDigest !== this.assessorSetDigest ||
235
+ claims.effectConsumerDigest !== boundary.effectConsumerDigest ||
236
+ claims.sinkId !== boundary.sinkId ||
237
+ claims.sinkKeyDigest !== boundary.sinkKeyDigest ||
238
+ claims.targetDigest !== input.expectedTargetDigest ||
239
+ claims.actionPayloadDigest !== input.expectedActionPayloadDigest ||
240
+ claims.committedStateRevision > current.revision ||
241
+ !retained ||
242
+ input.currentLogicalTimeMs < claims.validFromLogicalTimeMs ||
243
+ input.currentLogicalTimeMs > claims.validUntilLogicalTimeMs)
244
+ throw new TypeError("semantic_action_authorization_currentness_invalid");
245
+ return authorization;
246
+ }
247
+ async dispatchAuthorizedAction(input, sink) {
248
+ if (!sink || typeof sink !== "object")
249
+ throw new TypeError("semantic_action_effect_sink_invalid");
250
+ assertIdentifier(sink.sinkId, "sink.sinkId");
251
+ assertDigest(sink.sinkKeyDigest, "sink.sinkKeyDigest");
252
+ assertDigest(sink.effectConsumerDigest, "sink.effectConsumerDigest");
253
+ if (typeof sink.applyOnce !== "function" ||
254
+ typeof sink.verifyReceipt !== "function")
255
+ throw new TypeError("semantic_action_effect_sink_invalid");
256
+ const boundary = this.options.actionAuthorization;
257
+ if (!boundary)
258
+ throw new TypeError("semantic_action_authorization_boundary_required");
259
+ if (sink.effectConsumerDigest !== boundary.effectConsumerDigest ||
260
+ sink.sinkId !== boundary.sinkId ||
261
+ sink.sinkKeyDigest !== boundary.sinkKeyDigest)
262
+ throw new TypeError("semantic_action_effect_sink_binding_mismatch");
263
+ const authorization = await this.verifyActionAuthorization(input);
264
+ const effectReceipt = validateSemanticActionEffectReceiptV1(await sink.applyOnce({
265
+ authorization,
266
+ targetDigest: input.expectedTargetDigest,
267
+ actionPayloadDigest: input.expectedActionPayloadDigest,
268
+ }));
269
+ if (effectReceipt.authorizationDigest !== authorization.authorizationDigest ||
270
+ effectReceipt.effectConsumerDigest !== boundary.effectConsumerDigest ||
271
+ effectReceipt.sinkId !== boundary.sinkId ||
272
+ effectReceipt.sinkKeyDigest !== boundary.sinkKeyDigest ||
273
+ effectReceipt.committedAtLogicalTimeMs <
274
+ authorization.claims.validFromLogicalTimeMs ||
275
+ effectReceipt.committedAtLogicalTimeMs >
276
+ authorization.claims.validUntilLogicalTimeMs ||
277
+ effectReceipt.committedAtLogicalTimeMs > input.currentLogicalTimeMs ||
278
+ !(await sink.verifyReceipt(effectReceipt)))
279
+ throw new TypeError("semantic_action_effect_receipt_unverified");
280
+ return deepFreeze({ authorization, effectReceipt });
281
+ }
282
+ async dispatchAction(input, currentLogicalTimeMs, sink) {
283
+ assertSafeInteger(currentLogicalTimeMs, "currentLogicalTimeMs");
284
+ if (currentLogicalTimeMs > this.options.policy.limits.maximumLogicalTimeMs)
285
+ throw new RangeError("semantic_action_authorization_logical_time_exceeded");
286
+ const authorized = await this.authorizeAction(input);
287
+ if (!authorized.authorization)
288
+ return deepFreeze({ ...authorized, effectReceipt: null });
289
+ const request = validateSemanticControlRequestV1(input.request);
290
+ const dispatched = await this.dispatchAuthorizedAction({
291
+ authorizationId: authorized.authorization.claims.authorizationId,
292
+ authorizationDigest: authorized.authorization.authorizationDigest,
293
+ expectedTargetDigest: request.targetDigest,
294
+ expectedActionPayloadDigest: request.actionPayloadDigest,
295
+ currentLogicalTimeMs,
296
+ }, sink);
297
+ return deepFreeze({
298
+ decision: authorized.decision,
299
+ ...dispatched,
300
+ });
301
+ }
302
+ async evaluate(raw) {
303
+ const request = validateSemanticControlRequestV1(raw.request);
304
+ this.assertRequestBounds(request);
305
+ this.assertPayloadBinding(request, raw.interventionPayload);
306
+ const before = await this.loadOrInitial();
307
+ const replay = before.lastDecision;
308
+ if (replay?.requestDigest === request.requestDigest)
309
+ return replay;
310
+ this.assertForward(before, request.sequence, request.logicalTimeMs);
311
+ this.assertHistory(before, request.priorCourseActionDigests);
312
+ const outcomes = await Promise.all(this.options.assessors.map((assessor) => this.ask(assessor, request)));
313
+ let aggregate = this.aggregate(request, outcomes.filter((item) => item !== null));
314
+ const reasons = new Set(aggregate.reasonCodes);
315
+ let disposition = aggregate.disposition;
316
+ let ensembleDecision = null;
317
+ let ensembleVerdictDigest = null;
318
+ let interventionAllowed = null;
319
+ let interventionAssessmentDigests = [];
320
+ if (this.options.ensemble && disposition !== "block") {
321
+ try {
322
+ const ensembleInput = {
323
+ invocationId: request.requestId,
324
+ signalDigest: aggregate.assessmentDigest,
325
+ executionDomain: request.checkpoint === "pre_action" ? "action" : "inference",
326
+ surface: request.checkpoint === "pre_step" ? "input" : request.checkpoint === "post_output" ? "output" : "action",
327
+ modalities: request.modalities,
328
+ step: request.sequence,
329
+ logicalTimeMs: request.logicalTimeMs,
330
+ };
331
+ const ensemble = await this.options.ensemble.assess(ensembleInput);
332
+ const expectedEnsembleRequest = createAssessorEnsembleRequestV1({
333
+ schemaVersion: 1,
334
+ bindingDigest: this.options.ensemble.bindingDigest,
335
+ policyDigest: this.options.ensemble.policyDigest,
336
+ ...ensembleInput,
337
+ });
338
+ const { verdictDigest, ...verdictBody } = ensemble.verdict;
339
+ const verdict = createAssessorEnsembleVerdictV1(verdictBody);
340
+ if (ensemble.verdict.schemaVersion !== 1 ||
341
+ verdict.verdictDigest !== verdictDigest ||
342
+ verdict.requestDigest !== expectedEnsembleRequest.requestDigest ||
343
+ (verdict.decision === "allow" && !verdict.coverageComplete) ||
344
+ !(await this.options.ensemble.verifyVerdict({
345
+ requestDigest: expectedEnsembleRequest.requestDigest,
346
+ verdictDigest: verdict.verdictDigest,
347
+ })))
348
+ throw new TypeError("semantic_ensemble_verdict_binding_invalid");
349
+ ensembleDecision = verdict.decision;
350
+ ensembleVerdictDigest = verdict.verdictDigest;
351
+ if (ensembleDecision === "block") {
352
+ disposition = "block";
353
+ reasons.add("independent_ensemble_blocked");
354
+ }
355
+ else if (ensembleDecision === "modify") {
356
+ disposition = disposition === "abstain" ? "abstain" : "steer";
357
+ reasons.add("independent_ensemble_requested_modification");
358
+ }
359
+ else if (ensembleDecision === "unresolved") {
360
+ disposition = "abstain";
361
+ reasons.add("independent_ensemble_unresolved");
362
+ }
363
+ }
364
+ catch {
365
+ disposition = "block";
366
+ reasons.add("independent_ensemble_unavailable");
367
+ }
368
+ }
369
+ if (request.checkpoint === "pre_action" && disposition === "steer") {
370
+ disposition = "block";
371
+ reasons.add("pre_action_steering_requires_new_action");
372
+ }
373
+ if (request.checkpoint === "pre_action" && this.options.intervention && disposition === "allow") {
374
+ try {
375
+ const gate = await this.options.intervention.gateOperation({
376
+ operationId: request.requestId,
377
+ kind: "action",
378
+ step: request.sequence,
379
+ logicalTimeMs: request.logicalTimeMs,
380
+ payload: raw.interventionPayload,
381
+ });
382
+ await this.validateInterventionGate(request, raw.interventionPayload, gate);
383
+ interventionAllowed = gate.allowed;
384
+ interventionAssessmentDigests = gate.assessments
385
+ .map((item) => item.assessmentDigest)
386
+ .sort();
387
+ if (!gate.allowed) {
388
+ disposition = "block";
389
+ reasons.add("inference_intervention_gate_blocked");
390
+ }
391
+ }
392
+ catch {
393
+ disposition = "block";
394
+ interventionAllowed = false;
395
+ reasons.add("inference_intervention_gate_unavailable");
396
+ }
397
+ }
398
+ const finalReasons = [...reasons].sort().slice(0, this.options.policy.limits.maximumReasonCodes);
399
+ // The aggregate remains the semantic measurement. External gates are
400
+ // separately bound into the final decision and cannot rewrite its metrics.
401
+ aggregate = deepFreeze(aggregate);
402
+ return this.commitDecision(before, request, aggregate, disposition, {
403
+ ensembleDecision,
404
+ ensembleVerdictDigest,
405
+ interventionAllowed,
406
+ interventionAssessmentDigests,
407
+ reasons: finalReasons,
408
+ });
409
+ }
410
+ async ask(assessor, request) {
411
+ let timer;
412
+ try {
413
+ const timeout = new Promise((_, reject) => {
414
+ timer = setTimeout(() => reject(new Error("semantic_assessor_timeout")), this.options.policy.limits.assessorTimeoutMs);
415
+ });
416
+ const assessment = await Promise.race([Promise.resolve(assessor.assess(request)), timeout]);
417
+ return {
418
+ assessor,
419
+ assessment: validateSemanticAssessorAssessmentV1(assessment, assessor.descriptor, request, this.options.policy),
420
+ };
421
+ }
422
+ catch {
423
+ return null;
424
+ }
425
+ finally {
426
+ if (timer)
427
+ clearTimeout(timer);
428
+ }
429
+ }
430
+ aggregate(request, outcomes) {
431
+ const groups = new Map();
432
+ for (const outcome of outcomes) {
433
+ const values = groups.get(outcome.assessor.descriptor.independenceGroup) ?? [];
434
+ values.push(outcome);
435
+ groups.set(outcome.assessor.descriptor.independenceGroup, values);
436
+ }
437
+ const dimensionValues = new Map();
438
+ for (const dimension of SEMANTIC_CONTROL_DIMENSIONS_V1)
439
+ dimensionValues.set(dimension, []);
440
+ for (const groupOutcomes of groups.values()) {
441
+ for (const dimension of SEMANTIC_CONTROL_DIMENSIONS_V1) {
442
+ const key = dimensionMetricKey(dimension);
443
+ const values = groupOutcomes.map((item) => item.assessment.metrics[key]).filter((value) => value !== null);
444
+ if (!values.length)
445
+ continue;
446
+ const conservative = beneficialDimensions.has(dimension) ? Math.min(...values) : Math.max(...values);
447
+ dimensionValues.get(dimension)?.push(conservative);
448
+ }
449
+ }
450
+ const aggregateValue = (dimension) => {
451
+ const values = [...(dimensionValues.get(dimension) ?? [])].sort((a, b) => a - b);
452
+ if (!values.length)
453
+ return null;
454
+ if (dimension === "role_coherence" || dimension === "mission_alignment")
455
+ return values[0] ?? null;
456
+ if (dimension === "context_conflict" || dimension === "uncertainty")
457
+ return values[values.length - 1] ?? null;
458
+ const index = beneficialDimensions.has(dimension)
459
+ ? Math.floor((values.length - 1) / 2)
460
+ : Math.floor(values.length / 2);
461
+ return values[index] ?? null;
462
+ };
463
+ const metrics = deepFreeze({
464
+ roleCoherenceBps: aggregateValue("role_coherence"),
465
+ missionAlignmentBps: aggregateValue("mission_alignment"),
466
+ contextConflictBps: aggregateValue("context_conflict"),
467
+ uncertaintyBps: aggregateValue("uncertainty"),
468
+ courseActionDiversityBps: aggregateValue("course_action_diversity"),
469
+ courseActionNoveltyBps: aggregateValue("course_action_novelty"),
470
+ });
471
+ const dimensionGroupCounts = deepFreeze(Object.fromEntries(SEMANTIC_CONTROL_DIMENSIONS_V1.map((dimension) => [dimension, dimensionValues.get(dimension)?.length ?? 0])));
472
+ const enforcing = new Set(this.options.policy.enforcingAssessorIds);
473
+ const hardConstraintViolations = [...new Set(outcomes
474
+ .filter((item) => enforcing.has(item.assessor.descriptor.assessorId))
475
+ .flatMap((item) => item.assessment.hardConstraintViolations))].sort();
476
+ const reasons = new Set();
477
+ let disposition = "allow";
478
+ if (groups.size < this.options.policy.minimumIndependenceGroups) {
479
+ disposition = "abstain";
480
+ reasons.add("semantic_independence_quorum_unavailable");
481
+ }
482
+ if (requiredSemanticDimensions.some((dimension) => dimensionGroupCounts[dimension] < this.options.policy.minimumGroupsPerDimension)) {
483
+ disposition = "abstain";
484
+ reasons.add("semantic_dimension_coverage_incomplete");
485
+ }
486
+ if (request.checkpoint === "pre_step" &&
487
+ request.candidateCourseActionDigests.length > 0 &&
488
+ dimensionGroupCounts.course_action_diversity <
489
+ this.options.policy.minimumGroupsPerDimension) {
490
+ disposition = "abstain";
491
+ reasons.add("course_action_diversity_coverage_incomplete");
492
+ }
493
+ if (request.checkpoint === "pre_step" &&
494
+ request.selectedCourseActionDigest !== null &&
495
+ dimensionGroupCounts.course_action_novelty <
496
+ this.options.policy.minimumGroupsPerDimension) {
497
+ disposition = "abstain";
498
+ reasons.add("course_action_novelty_coverage_incomplete");
499
+ }
500
+ if (hardConstraintViolations.length) {
501
+ disposition = "block";
502
+ reasons.add("authoritative_hard_constraint_violation");
503
+ }
504
+ const t = this.options.policy.thresholds;
505
+ if (metrics.roleCoherenceBps !== null && metrics.roleCoherenceBps < t.minimumRoleCoherenceBps) {
506
+ disposition = "block";
507
+ reasons.add("role_coherence_below_hard_minimum");
508
+ }
509
+ if (metrics.missionAlignmentBps !== null && metrics.missionAlignmentBps < t.minimumMissionAlignmentBps) {
510
+ disposition = "block";
511
+ reasons.add("mission_alignment_below_hard_minimum");
512
+ }
513
+ if (metrics.contextConflictBps !== null && metrics.contextConflictBps > t.maximumContextConflictBps) {
514
+ disposition = request.checkpoint === "pre_action" ? "block" : disposition === "allow" ? "steer" : disposition;
515
+ reasons.add("context_conflict_above_maximum");
516
+ }
517
+ if (metrics.uncertaintyBps !== null && metrics.uncertaintyBps > t.maximumUncertaintyBps) {
518
+ disposition = request.checkpoint === "pre_action" ? "block" : disposition === "allow" ? "steer" : disposition;
519
+ reasons.add("semantic_uncertainty_above_maximum");
520
+ }
521
+ if (request.checkpoint === "pre_step") {
522
+ if (metrics.courseActionDiversityBps !== null && metrics.courseActionDiversityBps < t.minimumCourseActionDiversityBps) {
523
+ if (disposition === "allow")
524
+ disposition = "steer";
525
+ reasons.add("course_action_diversity_below_exploration_floor");
526
+ }
527
+ if (metrics.courseActionNoveltyBps !== null && metrics.courseActionNoveltyBps < t.minimumCourseActionNoveltyBps) {
528
+ if (disposition === "allow")
529
+ disposition = "steer";
530
+ reasons.add("course_action_novelty_below_exploration_floor");
531
+ }
532
+ }
533
+ if (outcomes.some((item) => item.assessment.recommendation === "steer" || item.assessment.recommendation === "block")) {
534
+ if (disposition === "allow")
535
+ disposition = "steer";
536
+ reasons.add("assessor_advisory_concern");
537
+ }
538
+ const evidenceDigests = [...new Set(outcomes.flatMap((item) => item.assessment.evidenceDigests))]
539
+ .sort()
540
+ .slice(0, this.options.policy.limits.maximumEvidenceDigests);
541
+ return createSemanticAggregateAssessmentV1({
542
+ schemaVersion: 1,
543
+ requestDigest: request.requestDigest,
544
+ disposition,
545
+ metrics,
546
+ hardConstraintViolations,
547
+ countedAssessorIds: outcomes.map((item) => item.assessor.descriptor.assessorId).sort(),
548
+ countedIndependenceGroups: [...groups.keys()].sort(),
549
+ dimensionGroupCounts,
550
+ missingAssessorIds: this.options.assessors
551
+ .map((item) => item.descriptor.assessorId)
552
+ .filter((id) => !outcomes.some((item) => item.assessor.descriptor.assessorId === id))
553
+ .sort(),
554
+ reasonCodes: [...reasons].sort().slice(0, this.options.policy.limits.maximumReasonCodes),
555
+ evidenceDigests,
556
+ });
557
+ }
558
+ async commitDecision(initial, request, aggregate, disposition, gates) {
559
+ let prior = initial;
560
+ for (let attempt = 0; attempt < this.options.policy.limits.maximumCommitAttempts; attempt++) {
561
+ const existing = prior.lastDecision;
562
+ if (existing?.requestDigest === request.requestDigest)
563
+ return existing;
564
+ this.assertForward(prior, request.sequence, request.logicalTimeMs);
565
+ this.assertHistory(prior, request.priorCourseActionDigests);
566
+ const proceed = disposition === "allow" ||
567
+ (request.checkpoint === "pre_step" && disposition === "steer");
568
+ const decisionBody = deepFreeze({
569
+ schemaVersion: 1,
570
+ requestId: request.requestId,
571
+ requestDigest: request.requestDigest,
572
+ checkpoint: request.checkpoint,
573
+ disposition,
574
+ proceed,
575
+ aggregate,
576
+ ensembleDecision: gates.ensembleDecision,
577
+ ensembleVerdictDigest: gates.ensembleVerdictDigest,
578
+ interventionAllowed: gates.interventionAllowed,
579
+ interventionAssessmentDigests: [...gates.interventionAssessmentDigests].sort(),
580
+ reasonCodes: [...gates.reasons],
581
+ priorStateRevision: prior.revision,
582
+ committedStateRevision: prior.revision + 1,
583
+ });
584
+ const decision = deepFreeze({
585
+ ...decisionBody,
586
+ decisionDigest: digestSemanticControlV1("decision", decisionBody),
587
+ });
588
+ const courseActionHistory = request.checkpoint !== "pre_step" ||
589
+ !proceed ||
590
+ request.selectedCourseActionDigest === null
591
+ ? prior.courseActionHistory
592
+ : [...prior.courseActionHistory, request.selectedCourseActionDigest]
593
+ .slice(-this.options.policy.limits.maximumCourseActionHistory);
594
+ const record = deepFreeze({
595
+ schemaVersion: 1,
596
+ requestDigest: request.requestDigest,
597
+ checkpoint: request.checkpoint,
598
+ sequence: request.sequence,
599
+ disposition,
600
+ aggregateAssessmentDigest: aggregate.assessmentDigest,
601
+ decisionDigest: decision.decisionDigest,
602
+ });
603
+ const stateBody = deepFreeze({
604
+ ...prior,
605
+ revision: prior.revision + 1,
606
+ sequenceHighWater: request.sequence,
607
+ logicalTimeHighWaterMs: request.logicalTimeMs,
608
+ courseActionHistory,
609
+ recentDecisions: [...prior.recentDecisions, record].slice(-this.options.policy.limits.maximumRetainedDecisions),
610
+ lastDecision: decision,
611
+ predecessorStateDigest: prior.stateDigest,
612
+ });
613
+ const { stateDigest: _old, ...withoutDigest } = stateBody;
614
+ const next = deepFreeze({
615
+ ...withoutDigest,
616
+ stateDigest: digestSemanticControlV1("state", withoutDigest),
617
+ });
618
+ if (await this.store.save({
619
+ state: next,
620
+ expectedRevision: prior.revision === 0 ? null : prior.revision,
621
+ expectedStateDigest: prior.revision === 0 ? null : prior.stateDigest,
622
+ })) {
623
+ const committed = await this.store.load(this.stateKey);
624
+ if (!committed)
625
+ throw new TypeError("semantic_committed_state_missing");
626
+ await this.validateState(committed);
627
+ return decision;
628
+ }
629
+ prior = await this.loadOrInitial();
630
+ }
631
+ throw new Error("semantic_state_commit_exhausted");
632
+ }
633
+ async loadOrInitial() {
634
+ const loaded = await this.store.load(this.stateKey);
635
+ if (loaded) {
636
+ await this.validateState(loaded);
637
+ return loaded;
638
+ }
639
+ if (await this.anchor.readAnchor(this.stateKey))
640
+ throw new TypeError("semantic_state_missing_below_anchor");
641
+ return createSemanticControlStateV1({
642
+ stateKey: this.stateKey,
643
+ bindingDigest: this.options.binding.bindingDigest,
644
+ policyDigest: this.options.policy.policyDigest,
645
+ assessorSetDigest: this.assessorSetDigest,
646
+ });
647
+ }
648
+ async validateState(state) {
649
+ validateSemanticControlStateV1(state, {
650
+ stateKey: this.stateKey,
651
+ bindingDigest: this.options.binding.bindingDigest,
652
+ policyDigest: this.options.policy.policyDigest,
653
+ assessorSetDigest: this.assessorSetDigest,
654
+ policy: this.options.policy,
655
+ });
656
+ const anchor = await this.anchor.readAnchor(this.stateKey);
657
+ if (state.revision > 0 &&
658
+ (!anchor ||
659
+ state.revision !== anchor.revision ||
660
+ state.sequenceHighWater !== anchor.sequenceHighWater ||
661
+ state.logicalTimeHighWaterMs !== anchor.logicalTimeHighWaterMs ||
662
+ state.stateDigest !== anchor.stateDigest))
663
+ throw new TypeError("semantic_state_anchor_mismatch");
664
+ }
665
+ assertRequestBounds(request) {
666
+ if (request.bindingDigest !== this.options.binding.bindingDigest ||
667
+ request.missionAnchorDigest !== this.options.binding.missionAnchorDigest ||
668
+ request.roleAnchorDigest !== this.options.binding.roleAnchorDigest ||
669
+ request.authorityDigest !== this.options.binding.authorityDigest)
670
+ throw new TypeError("semantic_request_binding_mismatch");
671
+ const limits = this.options.policy.limits;
672
+ if (request.sequence > limits.maximumSequence || request.logicalTimeMs > limits.maximumLogicalTimeMs)
673
+ throw new RangeError("semantic_request_bound_exceeded");
674
+ if (request.candidateCourseActionDigests.length > limits.maximumCourseActionCandidates || request.priorCourseActionDigests.length > limits.maximumCourseActionHistory)
675
+ throw new RangeError("semantic_course_action_bound_exceeded");
676
+ }
677
+ async validateInterventionGate(request, payload, gate) {
678
+ const port = this.options.intervention;
679
+ if (!gate || typeof gate.allowed !== "boolean" || !Array.isArray(gate.assessments))
680
+ throw new TypeError("semantic_intervention_gate_shape_invalid");
681
+ for (const assessment of gate.assessments)
682
+ validateInterventionAssessmentRecord(assessment);
683
+ const state = gate.state;
684
+ if (!state || typeof state !== "object")
685
+ throw new TypeError("semantic_intervention_state_missing");
686
+ const { stateDigest, ...stateBody } = state;
687
+ assertDigest(stateDigest, "intervention.stateDigest");
688
+ if (stateDigest !== digestInferenceInterventionV1("state", stateBody) ||
689
+ state.bindingDigest !== port.bindingDigest ||
690
+ state.policyDigest !== port.policyDigest ||
691
+ state.activeInvocation !== null ||
692
+ state.unresolvedEffect !== null)
693
+ throw new TypeError("semantic_intervention_state_binding_invalid");
694
+ const inputDigest = `sha256:${sha256Hex(encoder.encode(payload))}`;
695
+ const invocationDigest = digestInferenceInterventionV1("invocation-action", {
696
+ invocationId: request.requestId,
697
+ executionDomain: "action",
698
+ bindingDigest: port.bindingDigest,
699
+ policyDigest: port.policyDigest,
700
+ inputDigest,
701
+ contextDigests: [],
702
+ modalityManifestDigest: digestInferenceInterventionV1("modalities", []),
703
+ roleReinforcementDigest: null,
704
+ step: request.sequence,
705
+ logicalTimeMs: request.logicalTimeMs,
706
+ });
707
+ const terminal = state.lastInvocation;
708
+ if (!terminal ||
709
+ terminal.invocationId !== request.requestId ||
710
+ terminal.invocationDigest !== invocationDigest ||
711
+ terminal.executionDomain !== "action" ||
712
+ terminal.step !== request.sequence ||
713
+ state.lastInvocationDigest !== invocationDigest ||
714
+ state.stepHighWater !== request.sequence ||
715
+ state.logicalTimeHighWaterMs !== request.logicalTimeMs ||
716
+ (terminal.decision === "allowed") !== gate.allowed)
717
+ throw new TypeError("semantic_intervention_terminal_binding_invalid");
718
+ if (!(await port.verifyOperationGate({
719
+ operationId: request.requestId,
720
+ step: request.sequence,
721
+ logicalTimeMs: request.logicalTimeMs,
722
+ payload,
723
+ stateDigest,
724
+ allowed: gate.allowed,
725
+ })))
726
+ throw new TypeError("semantic_intervention_receipt_unverified");
727
+ }
728
+ assertPayloadBinding(request, payload) {
729
+ if (request.checkpoint !== "pre_action") {
730
+ if (payload !== undefined)
731
+ throw new TypeError("semantic_action_payload_outside_pre_action");
732
+ return;
733
+ }
734
+ if (payload === undefined || request.actionPayloadDigest === null)
735
+ throw new TypeError("semantic_action_payload_required");
736
+ if (digestSemanticOperationPayloadV1(payload, this.options.policy.limits.maximumActionPayloadBytes) !== request.actionPayloadDigest)
737
+ throw new TypeError("semantic_action_payload_digest_mismatch");
738
+ }
739
+ assertForward(state, sequence, logicalTimeMs) {
740
+ if (sequence <= state.sequenceHighWater || logicalTimeMs < state.logicalTimeHighWaterMs)
741
+ throw new RangeError("semantic_request_replay_or_reorder_rejected");
742
+ }
743
+ assertHistory(state, supplied) {
744
+ if (supplied.length !== state.courseActionHistory.length ||
745
+ supplied.some((digest, index) => digest !== state.courseActionHistory[index]))
746
+ throw new TypeError("semantic_course_action_history_mismatch");
747
+ }
748
+ requireCheckpoint(input, expected) {
749
+ if (input.request.checkpoint !== expected)
750
+ throw new TypeError(`semantic_checkpoint_mismatch:${expected}`);
751
+ }
752
+ }
753
+ function validateInterventionAssessmentRecord(value) {
754
+ if (!value ||
755
+ value.schemaVersion !== 1 ||
756
+ typeof value.assessorId !== "string" ||
757
+ value.assessorId.length === 0 ||
758
+ !Number.isSafeInteger(value.assessorVersion) ||
759
+ value.assessorVersion < 1 ||
760
+ !["allow", "modify", "block", "unavailable"].includes(value.decision) ||
761
+ [value.riskBps, value.uncertaintyBps, value.roleCoherenceBps].some((item) => !Number.isSafeInteger(item) || item < 0 || item > 10_000) ||
762
+ !Array.isArray(value.reasonCodes) ||
763
+ value.reasonCodes.length > 32 ||
764
+ value.reasonCodes.some((item) => typeof item !== "string" ||
765
+ item.length === 0 ||
766
+ encoder.encode(item).byteLength > 256) ||
767
+ !Array.isArray(value.evidenceDigests) ||
768
+ value.evidenceDigests.length > 32)
769
+ throw new TypeError("semantic_intervention_assessment_invalid");
770
+ assertDigest(value.assessorImplementationDigest, "assessorImplementationDigest");
771
+ for (const digest of value.evidenceDigests)
772
+ assertDigest(digest, "intervention.evidenceDigest");
773
+ const { assessmentDigest, ...body } = value;
774
+ assertDigest(assessmentDigest, "assessmentDigest");
775
+ if (assessmentDigest !== digestInferenceInterventionV1("assessment", body))
776
+ throw new TypeError("semantic_intervention_assessment_digest_invalid");
777
+ }
778
+ //# sourceMappingURL=semantic-alignment-runtime.js.map