@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,1512 @@
1
+ import { canonicalizeControlJsonV1, digestControlJsonV1 } from "./canonical.js";
2
+ import { CONTEXT_INTEGRITY_MEMORY_TIERS_V1, CONTEXT_INTEGRITY_SCHEMA_VERSION_V1, CONTEXT_INTEGRITY_SOURCE_ZONES_V1, CONTEXT_INTEGRITY_STATE_FORMAT_V1, } from "./context-integrity-contracts.js";
3
+ import { sha256Hex } from "./sha256.js";
4
+ import { assertDigest, assertExactKeys, assertIdentifier, assertOneOf, assertSafeInteger, assertStrictJsonValue, deepFreeze, sortedUnique, } from "./validation.js";
5
+ const encoder = new TextEncoder();
6
+ const checkpoints = [
7
+ "pre_inference",
8
+ "pre_step",
9
+ "post_output",
10
+ "pre_action",
11
+ ];
12
+ const targetKinds = ["context", "output", "action"];
13
+ const assessmentDispositions = [
14
+ "clear",
15
+ "caution",
16
+ "quarantine",
17
+ "deny",
18
+ "unavailable",
19
+ ];
20
+ const itemActions = [
21
+ "admit",
22
+ "restrict",
23
+ "isolate",
24
+ "require_corroboration",
25
+ "deny",
26
+ ];
27
+ const stateStatuses = ["active", "degraded", "paused", "denied"];
28
+ const policyKeys = [
29
+ "adverseSignalsToPause",
30
+ "allowEmptyAfterIsolation",
31
+ "allowedFilterBindingDigests",
32
+ "limits",
33
+ "minimumCorroborationGroups",
34
+ "parentPolicyDigest",
35
+ "policyId",
36
+ "policyVersion",
37
+ "recoverySignalsRequired",
38
+ "schemaVersion",
39
+ "thresholds",
40
+ "trustedSourceZones",
41
+ ];
42
+ const policyRecordKeys = ["policy", "policyDigest", "schemaVersion"];
43
+ const filterBindingKeys = [
44
+ "filterBindingDigest",
45
+ "filterId",
46
+ "filterImplementationDigest",
47
+ "filterVersion",
48
+ "schemaVersion",
49
+ ];
50
+ const thresholdKeys = [
51
+ "cautionRiskBps",
52
+ "contradictionRiskBps",
53
+ "denyRiskBps",
54
+ "maximumUncertaintyBps",
55
+ "quarantineRiskBps",
56
+ ];
57
+ const limitKeys = [
58
+ "maximumAssessmentTtlMs",
59
+ "maximumCommitAttempts",
60
+ "maximumCorroborationGroupsPerItem",
61
+ "maximumDecisionTtlMs",
62
+ "maximumEvidenceDigestsPerAssessment",
63
+ "maximumItemsPerRequest",
64
+ "maximumReasonCodesPerAssessment",
65
+ "maximumRetainedHeads",
66
+ "maximumSteps",
67
+ "maximumThreatKindsPerAssessment",
68
+ "rollingWindowAssessments",
69
+ ];
70
+ const itemKeys = [
71
+ "claimKeyDigest",
72
+ "claimValueDigest",
73
+ "contentDigest",
74
+ "corroborationGroupIds",
75
+ "expiresAtLogicalMs",
76
+ "itemDigest",
77
+ "itemId",
78
+ "memoryTier",
79
+ "observedAtLogicalMs",
80
+ "provenanceDigest",
81
+ "schemaVersion",
82
+ "sourceId",
83
+ "sourceRevision",
84
+ "sourceVersion",
85
+ "sourceZone",
86
+ ];
87
+ const scopeKeys = ["agentId", "objectiveId", "sessionId", "tenantId"];
88
+ const requestKeys = [
89
+ "checkpoint",
90
+ "filterBindingDigest",
91
+ "items",
92
+ "logicalTimeMs",
93
+ "requestDigest",
94
+ "requestId",
95
+ "schemaVersion",
96
+ "scope",
97
+ "targetKind",
98
+ ];
99
+ const contentKeys = ["content", "contentDigest", "itemId", "mediaType"];
100
+ const assessmentKeys = [
101
+ "analysisDigest",
102
+ "analyzerId",
103
+ "analyzerImplementationDigest",
104
+ "analyzerRevision",
105
+ "analyzerVersion",
106
+ "assessedAtLogicalMs",
107
+ "assessmentDigest",
108
+ "assessmentId",
109
+ "disposition",
110
+ "evidenceDigests",
111
+ "expiresAtLogicalMs",
112
+ "instructionConflictBps",
113
+ "itemDigest",
114
+ "itemId",
115
+ "reasonCodes",
116
+ "requestDigest",
117
+ "requestId",
118
+ "riskBps",
119
+ "schemaVersion",
120
+ "threatKinds",
121
+ "uncertaintyBps",
122
+ ];
123
+ const headKeys = [
124
+ "analysisDigest",
125
+ "analyzerId",
126
+ "analyzerRevision",
127
+ "assessmentDigest",
128
+ "contentDigest",
129
+ "expiresAtLogicalMs",
130
+ "headKey",
131
+ "itemId",
132
+ "schemaVersion",
133
+ "sourceId",
134
+ "sourceRevision",
135
+ "sourceVersion",
136
+ ];
137
+ const windowKeys = [
138
+ "deniedItems",
139
+ "evaluatedAtLogicalMs",
140
+ "isolatedItems",
141
+ "maximumRiskBps",
142
+ "maximumUncertaintyBps",
143
+ "requestDigest",
144
+ "schemaVersion",
145
+ ];
146
+ const interventionKeys = [
147
+ "corroborationRequired",
148
+ "denied",
149
+ "isolated",
150
+ "restricted",
151
+ ];
152
+ const itemDecisionKeys = [
153
+ "action",
154
+ "assessmentDigest",
155
+ "itemDigest",
156
+ "itemId",
157
+ "reasonCodes",
158
+ "riskBps",
159
+ "schemaVersion",
160
+ "uncertaintyBps",
161
+ ];
162
+ const decisionKeys = [
163
+ "analyzerId",
164
+ "analyzerImplementationDigest",
165
+ "analyzerVersion",
166
+ "committedStateRevision",
167
+ "controllerId",
168
+ "controllerVersion",
169
+ "decisionDigest",
170
+ "decisionId",
171
+ "degraded",
172
+ "disposition",
173
+ "evaluatedAtLogicalMs",
174
+ "expiresAtLogicalMs",
175
+ "filterRequired",
176
+ "implementationId",
177
+ "items",
178
+ "policyDigest",
179
+ "policyId",
180
+ "policyVersion",
181
+ "priorStateRevision",
182
+ "requestDigest",
183
+ "requestId",
184
+ "schemaVersion",
185
+ "stateStatus",
186
+ ];
187
+ const stateKeys = [
188
+ "adverseStreak",
189
+ "analyzerId",
190
+ "analyzerImplementationDigest",
191
+ "analyzerVersion",
192
+ "controllerId",
193
+ "controllerVersion",
194
+ "degraded",
195
+ "format",
196
+ "heads",
197
+ "implementationId",
198
+ "interventionCounts",
199
+ "lastDecision",
200
+ "lastRequestDigest",
201
+ "logicalTimeHighWaterMs",
202
+ "policyDigest",
203
+ "policyId",
204
+ "policyVersion",
205
+ "predecessorStateDigest",
206
+ "recoveryStreak",
207
+ "revision",
208
+ "rollingWindow",
209
+ "schemaVersion",
210
+ "stateDigest",
211
+ "stateKey",
212
+ "status",
213
+ "stepCount",
214
+ ];
215
+ const handoffKeys = [
216
+ "analyzerId",
217
+ "analyzerImplementationDigest",
218
+ "analyzerVersion",
219
+ "contentClass",
220
+ "controllerId",
221
+ "controllerVersion",
222
+ "exportedAtLogicalMs",
223
+ "handoffDigest",
224
+ "implementationId",
225
+ "policyDigest",
226
+ "schemaVersion",
227
+ "sourceState",
228
+ "sourceStateDigest",
229
+ "sourceStateKey",
230
+ "targetStateKey",
231
+ ];
232
+ export function digestContextIntegrityJsonV1(domain, value) {
233
+ return `sha256:${sha256Hex(encoder.encode(`agentplat.inference-control/context-integrity/${domain}/v1\0${canonicalizeControlJsonV1(value)}`))}`;
234
+ }
235
+ export function createContextIntegrityPolicyV1(input) {
236
+ const policy = normalizePolicy(input);
237
+ return freeze({
238
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
239
+ policy,
240
+ policyDigest: digestContextIntegrityJsonV1("policy", policy),
241
+ });
242
+ }
243
+ export function validateContextIntegrityPolicyV1(input) {
244
+ assertExactKeys(input, policyRecordKeys, "context integrity policy record");
245
+ const value = input;
246
+ if (value.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
247
+ fail("context_integrity_policy_schema_invalid");
248
+ const rebuilt = createContextIntegrityPolicyV1(value.policy);
249
+ if (value.policyDigest !== rebuilt.policyDigest)
250
+ fail("context_integrity_policy_digest_invalid");
251
+ return rebuilt;
252
+ }
253
+ export function createContextIntegrityFilterBindingV1(input) {
254
+ assertExactKeys(input, filterBindingKeys.filter((key) => key !== "filterBindingDigest"), "context integrity filter binding input");
255
+ if (input.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
256
+ fail("context_integrity_filter_binding_schema_invalid");
257
+ const body = freeze({
258
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
259
+ filterId: id(input.filterId, "filterId"),
260
+ filterVersion: positive(input.filterVersion, "filterVersion"),
261
+ filterImplementationDigest: sha(input.filterImplementationDigest, "filterImplementationDigest"),
262
+ });
263
+ return freeze({
264
+ ...body,
265
+ filterBindingDigest: digestContextIntegrityJsonV1("filter", body),
266
+ });
267
+ }
268
+ export function validateContextIntegrityFilterBindingV1(input) {
269
+ assertExactKeys(input, filterBindingKeys, "context integrity filter binding");
270
+ const value = input;
271
+ const rebuilt = createContextIntegrityFilterBindingV1({
272
+ schemaVersion: value.schemaVersion,
273
+ filterId: value.filterId,
274
+ filterVersion: value.filterVersion,
275
+ filterImplementationDigest: value.filterImplementationDigest,
276
+ });
277
+ if (value.filterBindingDigest !== rebuilt.filterBindingDigest)
278
+ fail("context_integrity_filter_binding_digest_invalid");
279
+ return rebuilt;
280
+ }
281
+ export function createContextIntegrityItemV1(input) {
282
+ assertExactKeys(input, itemKeys.filter((key) => key !== "itemDigest"), "context integrity item input");
283
+ if (input.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
284
+ fail("context_integrity_item_schema_invalid");
285
+ const claimKeyDigest = nullableDigest(input.claimKeyDigest, "claimKeyDigest");
286
+ const claimValueDigest = nullableDigest(input.claimValueDigest, "claimValueDigest");
287
+ if ((claimKeyDigest === null) !== (claimValueDigest === null))
288
+ fail("context_integrity_claim_binding_incomplete");
289
+ const body = freeze({
290
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
291
+ itemId: id(input.itemId, "itemId"),
292
+ sourceZone: sourceZone(input.sourceZone),
293
+ sourceId: id(input.sourceId, "sourceId"),
294
+ sourceVersion: positive(input.sourceVersion, "sourceVersion"),
295
+ sourceRevision: nonNegative(input.sourceRevision, "sourceRevision"),
296
+ memoryTier: memoryTier(input.memoryTier),
297
+ contentDigest: sha(input.contentDigest, "contentDigest"),
298
+ provenanceDigest: sha(input.provenanceDigest, "provenanceDigest"),
299
+ claimKeyDigest,
300
+ claimValueDigest,
301
+ corroborationGroupIds: tokens(input.corroborationGroupIds, "corroborationGroupIds", 32),
302
+ observedAtLogicalMs: nonNegative(input.observedAtLogicalMs, "observedAtLogicalMs"),
303
+ expiresAtLogicalMs: positive(input.expiresAtLogicalMs, "expiresAtLogicalMs"),
304
+ });
305
+ if (body.expiresAtLogicalMs <= body.observedAtLogicalMs)
306
+ fail("context_integrity_item_window_invalid");
307
+ return freeze({
308
+ ...body,
309
+ itemDigest: digestContextIntegrityJsonV1("item", body),
310
+ });
311
+ }
312
+ export function validateContextIntegrityItemV1(input) {
313
+ assertExactKeys(input, itemKeys, "context integrity item");
314
+ const value = input;
315
+ const { itemDigest, ...body } = value;
316
+ const rebuilt = createContextIntegrityItemV1(body);
317
+ if (itemDigest !== rebuilt.itemDigest)
318
+ fail("context_integrity_item_digest_invalid");
319
+ return rebuilt;
320
+ }
321
+ export function createContextIntegrityRequestV1(input) {
322
+ assertExactKeys(input, requestKeys.filter((key) => key !== "requestDigest"), "context integrity request input");
323
+ if (input.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
324
+ fail("context_integrity_request_schema_invalid");
325
+ if (!Array.isArray(input.items) || input.items.length > 256)
326
+ fail("context_integrity_request_items_invalid");
327
+ const items = input.items.map(validateContextIntegrityItemV1);
328
+ assertUnique(items.map(({ itemId }) => itemId), "context integrity item IDs");
329
+ const body = freeze({
330
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
331
+ requestId: id(input.requestId, "requestId"),
332
+ checkpoint: checkpoint(input.checkpoint),
333
+ targetKind: targetKind(input.targetKind),
334
+ scope: normalizeScope(input.scope),
335
+ logicalTimeMs: nonNegative(input.logicalTimeMs, "logicalTimeMs"),
336
+ filterBindingDigest: nullableDigest(input.filterBindingDigest, "filterBindingDigest"),
337
+ items: freeze(items),
338
+ });
339
+ if ((body.targetKind === "context" &&
340
+ body.checkpoint !== "pre_inference" &&
341
+ body.checkpoint !== "pre_step") ||
342
+ (body.targetKind === "output" && body.checkpoint !== "post_output") ||
343
+ (body.targetKind === "action" && body.checkpoint !== "pre_action"))
344
+ fail("context_integrity_checkpoint_target_invalid");
345
+ return freeze({
346
+ ...body,
347
+ requestDigest: digestContextIntegrityJsonV1("request", body),
348
+ });
349
+ }
350
+ export function validateContextIntegrityRequestV1(input) {
351
+ assertExactKeys(input, requestKeys, "context integrity request");
352
+ const value = input;
353
+ const { requestDigest, ...body } = value;
354
+ const rebuilt = createContextIntegrityRequestV1(body);
355
+ if (requestDigest !== rebuilt.requestDigest)
356
+ fail("context_integrity_request_digest_invalid");
357
+ return rebuilt;
358
+ }
359
+ export function createContextIntegrityEphemeralContentV1(input) {
360
+ assertExactKeys(input, ["content", "itemId", "mediaType"], "context integrity ephemeral content input");
361
+ assertStrictJsonValue(input.content);
362
+ return freeze({
363
+ itemId: id(input.itemId, "content.itemId"),
364
+ mediaType: oneOf(input.mediaType, ["text", "json"], "content.mediaType"),
365
+ content: cloneJson(input.content),
366
+ contentDigest: digestControlJsonV1("context", input.content),
367
+ });
368
+ }
369
+ export function validateContextIntegrityEphemeralContentV1(input) {
370
+ assertExactKeys(input, contentKeys, "context integrity ephemeral content");
371
+ const value = input;
372
+ const rebuilt = createContextIntegrityEphemeralContentV1({
373
+ itemId: value.itemId,
374
+ mediaType: value.mediaType,
375
+ content: value.content,
376
+ });
377
+ if (value.contentDigest !== rebuilt.contentDigest)
378
+ fail("context_integrity_content_digest_invalid");
379
+ return rebuilt;
380
+ }
381
+ export function createContextIntegrityAssessmentV1(input) {
382
+ assertExactKeys(input, assessmentKeys.filter((key) => key !== "analysisDigest" && key !== "assessmentDigest"), "context integrity assessment input");
383
+ if (input.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
384
+ fail("context_integrity_assessment_schema_invalid");
385
+ const assessedAtLogicalMs = nonNegative(input.assessedAtLogicalMs, "assessedAtLogicalMs");
386
+ const expiresAtLogicalMs = positive(input.expiresAtLogicalMs, "expiresAtLogicalMs");
387
+ if (expiresAtLogicalMs <= assessedAtLogicalMs)
388
+ fail("context_integrity_assessment_window_invalid");
389
+ const analysisBody = freeze({
390
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
391
+ itemId: id(input.itemId, "assessment.itemId"),
392
+ itemDigest: sha(input.itemDigest, "assessment.itemDigest"),
393
+ analyzerId: id(input.analyzerId, "assessment.analyzerId"),
394
+ analyzerVersion: positive(input.analyzerVersion, "assessment.analyzerVersion"),
395
+ analyzerImplementationDigest: sha(input.analyzerImplementationDigest, "assessment.analyzerImplementationDigest"),
396
+ analyzerRevision: nonNegative(input.analyzerRevision, "assessment.analyzerRevision"),
397
+ disposition: assessmentDisposition(input.disposition),
398
+ riskBps: bps(input.riskBps, "assessment.riskBps"),
399
+ uncertaintyBps: bps(input.uncertaintyBps, "assessment.uncertaintyBps"),
400
+ instructionConflictBps: bps(input.instructionConflictBps, "assessment.instructionConflictBps"),
401
+ threatKinds: tokens(input.threatKinds, "assessment.threatKinds", 32),
402
+ reasonCodes: tokens(input.reasonCodes, "assessment.reasonCodes", 32),
403
+ evidenceDigests: digests(input.evidenceDigests, "assessment.evidenceDigests", 32),
404
+ });
405
+ const analysisDigest = digestContextIntegrityJsonV1("analysis", analysisBody);
406
+ const body = freeze({
407
+ assessmentId: id(input.assessmentId, "assessmentId"),
408
+ requestId: id(input.requestId, "assessment.requestId"),
409
+ requestDigest: sha(input.requestDigest, "assessment.requestDigest"),
410
+ ...analysisBody,
411
+ assessedAtLogicalMs,
412
+ expiresAtLogicalMs,
413
+ analysisDigest,
414
+ });
415
+ return freeze({
416
+ ...body,
417
+ assessmentDigest: digestContextIntegrityJsonV1("assessment", body),
418
+ });
419
+ }
420
+ export function validateContextIntegrityAssessmentV1(input) {
421
+ assertExactKeys(input, assessmentKeys, "context integrity assessment");
422
+ const value = input;
423
+ const { analysisDigest, assessmentDigest, ...body } = value;
424
+ const rebuilt = createContextIntegrityAssessmentV1(body);
425
+ if (analysisDigest !== rebuilt.analysisDigest ||
426
+ assessmentDigest !== rebuilt.assessmentDigest)
427
+ fail("context_integrity_assessment_digest_invalid");
428
+ return rebuilt;
429
+ }
430
+ export function createContextIntegrityStateV1(input) {
431
+ const policy = validateContextIntegrityPolicyV1(input.policy);
432
+ const heads = normalizeHeads(input.heads ?? []);
433
+ if (heads.length > policy.policy.limits.maximumRetainedHeads)
434
+ fail("context_integrity_head_capacity_exceeded");
435
+ const rollingWindow = normalizeWindow(input.rollingWindow ?? []);
436
+ if (rollingWindow.length > policy.policy.limits.rollingWindowAssessments)
437
+ fail("context_integrity_window_capacity_exceeded");
438
+ const lastDecision = input.lastDecision === undefined || input.lastDecision === null
439
+ ? null
440
+ : normalizeDecision(input.lastDecision);
441
+ const lastRequestDigest = input.lastRequestDigest === undefined || input.lastRequestDigest === null
442
+ ? null
443
+ : sha(input.lastRequestDigest, "state.lastRequestDigest");
444
+ if ((lastRequestDigest === null) !== (lastDecision === null) ||
445
+ (lastDecision && lastDecision.requestDigest !== lastRequestDigest))
446
+ fail("context_integrity_retained_decision_invalid");
447
+ const counts = normalizeInterventionCounts(input.interventionCounts ?? {
448
+ restricted: 0,
449
+ isolated: 0,
450
+ corroborationRequired: 0,
451
+ denied: 0,
452
+ });
453
+ const body = freeze({
454
+ format: CONTEXT_INTEGRITY_STATE_FORMAT_V1,
455
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
456
+ stateKey: id(input.stateKey, "stateKey"),
457
+ controllerId: id(input.controllerId, "controllerId"),
458
+ controllerVersion: positive(input.controllerVersion, "controllerVersion"),
459
+ implementationId: id(input.implementationId, "implementationId"),
460
+ policyId: policy.policy.policyId,
461
+ policyVersion: policy.policy.policyVersion,
462
+ policyDigest: policy.policyDigest,
463
+ analyzerId: id(input.analyzer.analyzerId, "analyzerId"),
464
+ analyzerVersion: positive(input.analyzer.analyzerVersion, "analyzerVersion"),
465
+ analyzerImplementationDigest: sha(input.analyzer.analyzerImplementationDigest, "analyzerImplementationDigest"),
466
+ revision: nonNegative(input.revision ?? 0, "state.revision"),
467
+ logicalTimeHighWaterMs: nonNegative(input.logicalTimeHighWaterMs ?? 0, "state.logicalTimeHighWaterMs"),
468
+ stepCount: nonNegative(input.stepCount ?? 0, "state.stepCount"),
469
+ status: stateStatus(input.status ?? "active"),
470
+ degraded: boolean(input.degraded ?? false, "state.degraded"),
471
+ adverseStreak: nonNegative(input.adverseStreak ?? 0, "state.adverseStreak"),
472
+ recoveryStreak: nonNegative(input.recoveryStreak ?? 0, "state.recoveryStreak"),
473
+ interventionCounts: counts,
474
+ heads,
475
+ rollingWindow,
476
+ predecessorStateDigest: input.predecessorStateDigest === undefined ||
477
+ input.predecessorStateDigest === null
478
+ ? null
479
+ : sha(input.predecessorStateDigest, "state.predecessorStateDigest"),
480
+ lastRequestDigest,
481
+ lastDecision,
482
+ });
483
+ if (body.stepCount > policy.policy.limits.maximumSteps)
484
+ fail("context_integrity_step_capacity_exceeded");
485
+ if (body.degraded !== (body.status !== "active") ||
486
+ (body.adverseStreak > 0 && body.recoveryStreak > 0) ||
487
+ body.heads.some(({ analyzerId }) => analyzerId !== body.analyzerId) ||
488
+ body.rollingWindow.length > body.stepCount ||
489
+ (body.rollingWindow.at(-1)?.evaluatedAtLogicalMs ?? 0) >
490
+ body.logicalTimeHighWaterMs ||
491
+ (body.lastDecision !== null &&
492
+ (body.lastDecision.controllerId !== body.controllerId ||
493
+ body.lastDecision.controllerVersion !== body.controllerVersion ||
494
+ body.lastDecision.implementationId !== body.implementationId ||
495
+ body.lastDecision.policyId !== body.policyId ||
496
+ body.lastDecision.policyVersion !== body.policyVersion ||
497
+ body.lastDecision.policyDigest !== body.policyDigest ||
498
+ body.lastDecision.analyzerId !== body.analyzerId ||
499
+ body.lastDecision.analyzerVersion !== body.analyzerVersion ||
500
+ body.lastDecision.analyzerImplementationDigest !==
501
+ body.analyzerImplementationDigest ||
502
+ body.lastDecision.committedStateRevision !== body.revision ||
503
+ body.lastDecision.evaluatedAtLogicalMs > body.logicalTimeHighWaterMs ||
504
+ body.lastDecision.stateStatus !== body.status ||
505
+ body.lastDecision.degraded !== body.degraded)))
506
+ fail("context_integrity_state_internal_binding_invalid");
507
+ return freeze({
508
+ ...body,
509
+ stateDigest: digestContextIntegrityJsonV1("state", body),
510
+ });
511
+ }
512
+ export function validateContextIntegrityStateV1(input, policyValue) {
513
+ assertExactKeys(input, stateKeys, "context integrity state");
514
+ const value = input;
515
+ if (value.format !== CONTEXT_INTEGRITY_STATE_FORMAT_V1 ||
516
+ value.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
517
+ fail("context_integrity_state_format_invalid");
518
+ const rebuilt = createContextIntegrityStateV1({
519
+ stateKey: value.stateKey,
520
+ controllerId: value.controllerId,
521
+ controllerVersion: value.controllerVersion,
522
+ implementationId: value.implementationId,
523
+ policy: policyValue,
524
+ analyzer: value,
525
+ revision: value.revision,
526
+ logicalTimeHighWaterMs: value.logicalTimeHighWaterMs,
527
+ stepCount: value.stepCount,
528
+ status: value.status,
529
+ degraded: value.degraded,
530
+ adverseStreak: value.adverseStreak,
531
+ recoveryStreak: value.recoveryStreak,
532
+ interventionCounts: value.interventionCounts,
533
+ heads: value.heads,
534
+ rollingWindow: value.rollingWindow,
535
+ predecessorStateDigest: value.predecessorStateDigest,
536
+ lastRequestDigest: value.lastRequestDigest,
537
+ lastDecision: value.lastDecision,
538
+ });
539
+ if (value.policyId !== rebuilt.policyId ||
540
+ value.policyVersion !== rebuilt.policyVersion ||
541
+ value.policyDigest !== rebuilt.policyDigest ||
542
+ value.stateDigest !== rebuilt.stateDigest)
543
+ fail("context_integrity_state_binding_invalid");
544
+ return rebuilt;
545
+ }
546
+ export function reduceContextIntegrityV1(input) {
547
+ const policy = validateContextIntegrityPolicyV1(input.policy);
548
+ const state = validateContextIntegrityStateV1(input.state, policy);
549
+ const request = validateContextIntegrityRequestV1(input.request);
550
+ assertStateBindings(state, policy);
551
+ if (request.items.length > policy.policy.limits.maximumItemsPerRequest)
552
+ fail("context_integrity_request_capacity_exceeded");
553
+ if (state.lastRequestDigest === request.requestDigest &&
554
+ state.lastDecision !== null)
555
+ return freeze({ state, decision: state.lastDecision });
556
+ if (state.stepCount >= policy.policy.limits.maximumSteps)
557
+ fail("context_integrity_step_capacity_exceeded");
558
+ const assessments = normalizeAssessments(input.assessments, policy.policy.limits);
559
+ const byItem = new Map();
560
+ for (const assessment of assessments) {
561
+ if (byItem.has(assessment.itemId))
562
+ fail("context_integrity_assessment_duplicated");
563
+ byItem.set(assessment.itemId, assessment);
564
+ }
565
+ const itemIds = new Set(request.items.map(({ itemId }) => itemId));
566
+ if ([...byItem.keys()].some((itemId) => !itemIds.has(itemId)))
567
+ fail("context_integrity_assessment_outside_request");
568
+ const contradictionKeys = contradictoryClaimKeys(request.items);
569
+ const headRetentionTime = Math.max(state.logicalTimeHighWaterMs, request.logicalTimeMs);
570
+ const headMap = new Map(state.heads
571
+ .filter(({ expiresAtLogicalMs }) => expiresAtLogicalMs > headRetentionTime)
572
+ .map((head) => [head.headKey, head]));
573
+ const decisions = [];
574
+ let maximumRiskBps = 0;
575
+ let maximumUncertaintyBps = 0;
576
+ let expiry = safeAdd(request.logicalTimeMs, policy.policy.limits.maximumDecisionTtlMs, "context_integrity_decision_expiry_overflow");
577
+ const logicalRollback = request.logicalTimeMs < state.logicalTimeHighWaterMs;
578
+ for (const item of request.items) {
579
+ const assessment = byItem.get(item.itemId);
580
+ const reasons = new Set();
581
+ let action = "admit";
582
+ let riskBps = assessment?.riskBps ?? 10_000;
583
+ let uncertaintyBps = assessment?.uncertaintyBps ?? 10_000;
584
+ let acceptedAssessmentDigest = null;
585
+ if (logicalRollback) {
586
+ action = "isolate";
587
+ reasons.add("logical_time_rollback");
588
+ }
589
+ else if (item.observedAtLogicalMs > request.logicalTimeMs ||
590
+ item.expiresAtLogicalMs <= request.logicalTimeMs) {
591
+ action = "isolate";
592
+ reasons.add(item.observedAtLogicalMs > request.logicalTimeMs
593
+ ? "item_future_dated"
594
+ : "item_expired");
595
+ }
596
+ else if (!assessment) {
597
+ action = "isolate";
598
+ reasons.add("assessment_missing");
599
+ }
600
+ else if (assessment.requestId !== request.requestId ||
601
+ assessment.requestDigest !== request.requestDigest ||
602
+ assessment.itemId !== item.itemId ||
603
+ assessment.itemDigest !== item.itemDigest ||
604
+ assessment.analyzerId !== state.analyzerId ||
605
+ assessment.analyzerVersion !== state.analyzerVersion ||
606
+ assessment.analyzerImplementationDigest !==
607
+ state.analyzerImplementationDigest) {
608
+ fail("context_integrity_assessment_binding_invalid");
609
+ }
610
+ else if (assessment.assessedAtLogicalMs > request.logicalTimeMs ||
611
+ assessment.expiresAtLogicalMs <= request.logicalTimeMs) {
612
+ action = "isolate";
613
+ reasons.add(assessment.assessedAtLogicalMs > request.logicalTimeMs
614
+ ? "assessment_future_dated"
615
+ : "assessment_expired");
616
+ }
617
+ else {
618
+ const headKey = contextIntegrityHeadKeyV1({
619
+ itemId: item.itemId,
620
+ sourceId: item.sourceId,
621
+ analyzerId: assessment.analyzerId,
622
+ });
623
+ const prior = headMap.get(headKey);
624
+ const sourceRollback = prior !== undefined &&
625
+ (item.sourceVersion < prior.sourceVersion ||
626
+ (item.sourceVersion === prior.sourceVersion &&
627
+ item.sourceRevision < prior.sourceRevision));
628
+ const sameSourceRevision = prior !== undefined &&
629
+ item.sourceVersion === prior.sourceVersion &&
630
+ item.sourceRevision === prior.sourceRevision;
631
+ if (prior &&
632
+ (sourceRollback ||
633
+ (sameSourceRevision &&
634
+ assessment.analyzerRevision < prior.analyzerRevision))) {
635
+ action = "isolate";
636
+ reasons.add("assessment_revision_rollback");
637
+ }
638
+ else if (prior &&
639
+ (item.sourceId !== prior.sourceId ||
640
+ (sameSourceRevision && item.contentDigest !== prior.contentDigest) ||
641
+ (sameSourceRevision &&
642
+ assessment.analyzerRevision === prior.analyzerRevision &&
643
+ assessment.analysisDigest !== prior.analysisDigest))) {
644
+ action = "deny";
645
+ reasons.add("assessment_equivocation");
646
+ }
647
+ else {
648
+ const isNew = !prior;
649
+ if (isNew &&
650
+ headMap.size >= policy.policy.limits.maximumRetainedHeads) {
651
+ action = "isolate";
652
+ reasons.add("state_capacity_exceeded");
653
+ }
654
+ else {
655
+ headMap.set(headKey, headFrom(item, assessment));
656
+ acceptedAssessmentDigest = assessment.assessmentDigest;
657
+ expiry = Math.min(expiry, item.expiresAtLogicalMs, assessment.expiresAtLogicalMs);
658
+ for (const reason of assessment.reasonCodes)
659
+ reasons.add(reason);
660
+ action = decideItemAction({
661
+ item,
662
+ assessment,
663
+ policy: policy.policy,
664
+ contradictory: item.claimKeyDigest
665
+ ? contradictionKeys.has(item.claimKeyDigest)
666
+ : false,
667
+ reasons,
668
+ });
669
+ }
670
+ }
671
+ }
672
+ maximumRiskBps = Math.max(maximumRiskBps, riskBps);
673
+ maximumUncertaintyBps = Math.max(maximumUncertaintyBps, uncertaintyBps);
674
+ decisions.push(freeze({
675
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
676
+ itemId: item.itemId,
677
+ itemDigest: item.itemDigest,
678
+ action,
679
+ riskBps,
680
+ uncertaintyBps,
681
+ reasonCodes: freeze([...reasons].sort(compare)),
682
+ assessmentDigest: acceptedAssessmentDigest,
683
+ }));
684
+ }
685
+ const filterRequired = decisions.some(({ action }) => action === "isolate" || action === "require_corroboration");
686
+ const deniedItems = decisions.filter(({ action }) => action === "deny").length;
687
+ const isolatedItems = decisions.filter(({ action }) => action === "isolate").length;
688
+ const corroborationRequired = decisions.filter(({ action }) => action === "require_corroboration").length;
689
+ const restrictedItems = decisions.filter(({ action }) => action === "restrict").length;
690
+ const admittedItems = decisions.length - deniedItems - isolatedItems - corroborationRequired;
691
+ const filterAllowed = request.filterBindingDigest !== null &&
692
+ policy.policy.allowedFilterBindingDigests.includes(request.filterBindingDigest);
693
+ const adverse = deniedItems > 0 ||
694
+ isolatedItems > 0 ||
695
+ corroborationRequired > 0 ||
696
+ restrictedItems > 0;
697
+ const adverseStreak = adverse ? state.adverseStreak + 1 : 0;
698
+ const recoveryStreak = adverse ? 0 : state.recoveryStreak + 1;
699
+ let status = adverse
700
+ ? "degraded"
701
+ : state.status;
702
+ if (state.status === "denied")
703
+ status = "denied";
704
+ else if (deniedItems > 0 &&
705
+ decisions.some(({ reasonCodes }) => reasonCodes.includes("assessment_equivocation")))
706
+ status = "denied";
707
+ else if (adverseStreak >= policy.policy.adverseSignalsToPause ||
708
+ (state.status === "paused" &&
709
+ recoveryStreak < policy.policy.recoverySignalsRequired))
710
+ status = "paused";
711
+ else if (!adverse && recoveryStreak >= policy.policy.recoverySignalsRequired)
712
+ status = "active";
713
+ let disposition = "allow";
714
+ if (deniedItems > 0 || status === "denied")
715
+ disposition = "deny";
716
+ else if (status === "paused" ||
717
+ (filterRequired && !filterAllowed) ||
718
+ (filterRequired &&
719
+ admittedItems === 0 &&
720
+ !policy.policy.allowEmptyAfterIsolation))
721
+ disposition = "abstain";
722
+ const priorStateRevision = state.revision;
723
+ const committedStateRevision = state.revision + 1;
724
+ const decisionBody = freeze({
725
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
726
+ controllerId: state.controllerId,
727
+ controllerVersion: state.controllerVersion,
728
+ implementationId: state.implementationId,
729
+ policyId: state.policyId,
730
+ policyVersion: state.policyVersion,
731
+ policyDigest: state.policyDigest,
732
+ analyzerId: state.analyzerId,
733
+ analyzerVersion: state.analyzerVersion,
734
+ analyzerImplementationDigest: state.analyzerImplementationDigest,
735
+ requestId: request.requestId,
736
+ requestDigest: request.requestDigest,
737
+ evaluatedAtLogicalMs: request.logicalTimeMs,
738
+ expiresAtLogicalMs: expiry,
739
+ priorStateRevision,
740
+ committedStateRevision,
741
+ disposition,
742
+ filterRequired,
743
+ stateStatus: status,
744
+ degraded: status !== "active" || adverse,
745
+ items: freeze(decisions),
746
+ });
747
+ const decisionDigest = digestContextIntegrityJsonV1("decision", decisionBody);
748
+ const decision = freeze({
749
+ ...decisionBody,
750
+ decisionId: `context-integrity-decision.${decisionDigest.slice(7)}`,
751
+ decisionDigest,
752
+ });
753
+ const nextWindow = [
754
+ ...state.rollingWindow,
755
+ freeze({
756
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
757
+ requestDigest: request.requestDigest,
758
+ maximumRiskBps,
759
+ maximumUncertaintyBps,
760
+ isolatedItems: isolatedItems + corroborationRequired,
761
+ deniedItems,
762
+ evaluatedAtLogicalMs: Math.max(state.logicalTimeHighWaterMs, request.logicalTimeMs),
763
+ }),
764
+ ].slice(-policy.policy.limits.rollingWindowAssessments);
765
+ const nextState = createContextIntegrityStateV1({
766
+ stateKey: state.stateKey,
767
+ controllerId: state.controllerId,
768
+ controllerVersion: state.controllerVersion,
769
+ implementationId: state.implementationId,
770
+ policy,
771
+ analyzer: state,
772
+ revision: committedStateRevision,
773
+ logicalTimeHighWaterMs: Math.max(state.logicalTimeHighWaterMs, request.logicalTimeMs),
774
+ stepCount: state.stepCount + 1,
775
+ status,
776
+ degraded: decision.degraded,
777
+ adverseStreak,
778
+ recoveryStreak,
779
+ interventionCounts: {
780
+ restricted: state.interventionCounts.restricted + restrictedItems,
781
+ isolated: state.interventionCounts.isolated + isolatedItems,
782
+ corroborationRequired: state.interventionCounts.corroborationRequired + corroborationRequired,
783
+ denied: state.interventionCounts.denied + deniedItems,
784
+ },
785
+ heads: freeze([...headMap.values()].sort(headOrder)),
786
+ rollingWindow: freeze(nextWindow),
787
+ predecessorStateDigest: state.predecessorStateDigest,
788
+ lastRequestDigest: request.requestDigest,
789
+ lastDecision: decision,
790
+ });
791
+ return freeze({ state: nextState, decision });
792
+ }
793
+ export function validateContextIntegrityDecisionV1(input) {
794
+ const request = validateContextIntegrityRequestV1(input.request);
795
+ const decision = normalizeDecision(input.decision);
796
+ if (decision.controllerId !== input.expected.controllerId ||
797
+ decision.controllerVersion !== input.expected.controllerVersion ||
798
+ decision.implementationId !== input.expected.implementationId ||
799
+ decision.policyId !== input.expected.policyId ||
800
+ decision.policyVersion !== input.expected.policyVersion ||
801
+ decision.policyDigest !== input.expected.policyDigest ||
802
+ decision.analyzerId !== input.expected.analyzerId ||
803
+ decision.analyzerVersion !== input.expected.analyzerVersion ||
804
+ decision.analyzerImplementationDigest !==
805
+ input.expected.analyzerImplementationDigest ||
806
+ decision.requestId !== request.requestId ||
807
+ decision.requestDigest !== request.requestDigest ||
808
+ decision.evaluatedAtLogicalMs !== request.logicalTimeMs ||
809
+ decision.expiresAtLogicalMs <= input.logicalTimeMs ||
810
+ decision.items.length !== request.items.length ||
811
+ decision.items.some((itemDecision, index) => itemDecision.itemId !== request.items[index]?.itemId ||
812
+ itemDecision.itemDigest !== request.items[index]?.itemDigest))
813
+ fail("context_integrity_decision_binding_invalid");
814
+ return decision;
815
+ }
816
+ export class ContextIntegrityRuntimeV1 {
817
+ controllerId;
818
+ controllerVersion;
819
+ implementationId;
820
+ policyId;
821
+ policyVersion;
822
+ policyDigest;
823
+ analyzerId;
824
+ analyzerVersion;
825
+ analyzerImplementationDigest;
826
+ #policy;
827
+ #analyzer;
828
+ #store;
829
+ constructor(options) {
830
+ if (!options || typeof options !== "object")
831
+ fail("context_integrity_runtime_options_required");
832
+ this.controllerId = id(options.controllerId, "controllerId");
833
+ this.controllerVersion = positive(options.controllerVersion, "controllerVersion");
834
+ this.implementationId = id(options.implementationId, "implementationId");
835
+ this.#policy = validateContextIntegrityPolicyV1(options.policy);
836
+ this.policyId = this.#policy.policy.policyId;
837
+ this.policyVersion = this.#policy.policy.policyVersion;
838
+ this.policyDigest = this.#policy.policyDigest;
839
+ if (!options.analyzer || typeof options.analyzer.analyze !== "function")
840
+ fail("context_integrity_analyzer_required");
841
+ this.analyzerId = id(options.analyzer.analyzerId, "analyzerId");
842
+ this.analyzerVersion = positive(options.analyzer.analyzerVersion, "analyzerVersion");
843
+ this.analyzerImplementationDigest = sha(options.analyzer.analyzerImplementationDigest, "analyzerImplementationDigest");
844
+ if (!options.store ||
845
+ typeof options.store.load !== "function" ||
846
+ typeof options.store.save !== "function")
847
+ fail("context_integrity_store_required");
848
+ this.#analyzer = options.analyzer;
849
+ this.#store = options.store;
850
+ }
851
+ async evaluate(input) {
852
+ assertExactKeys(input, ["contents", "request", "stateKey"], "context integrity evaluation");
853
+ const stateKey = id(input.stateKey, "stateKey");
854
+ const request = validateContextIntegrityRequestV1(input.request);
855
+ if (request.items.length > this.#policy.policy.limits.maximumItemsPerRequest)
856
+ fail("context_integrity_request_capacity_exceeded");
857
+ const contents = normalizeContents(input.contents, request);
858
+ let loaded = await this.#store.load(stateKey);
859
+ let logicalRollback = false;
860
+ if (loaded) {
861
+ const retained = validateContextIntegrityStateV1(loaded, this.#policy);
862
+ assertRuntimeStateBinding(retained, this);
863
+ if (retained.lastRequestDigest === request.requestDigest &&
864
+ retained.lastDecision !== null)
865
+ return retained.lastDecision;
866
+ logicalRollback = request.logicalTimeMs < retained.logicalTimeHighWaterMs;
867
+ }
868
+ const assessmentResults = await Promise.all(request.items.map(async (item) => {
869
+ if (logicalRollback ||
870
+ item.observedAtLogicalMs > request.logicalTimeMs ||
871
+ item.expiresAtLogicalMs <= request.logicalTimeMs)
872
+ return null;
873
+ return validateContextIntegrityAssessmentV1(await this.#analyzer.analyze({
874
+ request,
875
+ item,
876
+ content: contents.get(item.itemId),
877
+ }));
878
+ }));
879
+ const assessments = assessmentResults.filter((assessment) => assessment !== null);
880
+ for (let attempt = 0; attempt < this.#policy.policy.limits.maximumCommitAttempts; attempt += 1) {
881
+ if (attempt > 0)
882
+ loaded = await this.#store.load(stateKey);
883
+ const state = loaded
884
+ ? validateContextIntegrityStateV1(loaded, this.#policy)
885
+ : createContextIntegrityStateV1({
886
+ stateKey,
887
+ controllerId: this.controllerId,
888
+ controllerVersion: this.controllerVersion,
889
+ implementationId: this.implementationId,
890
+ policy: this.#policy,
891
+ analyzer: this,
892
+ });
893
+ assertRuntimeStateBinding(state, this);
894
+ const result = reduceContextIntegrityV1({
895
+ state,
896
+ policy: this.#policy,
897
+ request,
898
+ assessments,
899
+ });
900
+ if (result.state.revision === state.revision)
901
+ return result.decision;
902
+ if (await this.#store.save({
903
+ state: result.state,
904
+ expectedRevision: loaded ? state.revision : null,
905
+ }))
906
+ return result.decision;
907
+ }
908
+ throw new Error("context_integrity_commit_conflict");
909
+ }
910
+ async getState(stateKeyValue) {
911
+ const stateKey = id(stateKeyValue, "stateKey");
912
+ const state = await this.#store.load(stateKey);
913
+ if (!state)
914
+ return null;
915
+ const validated = validateContextIntegrityStateV1(state, this.#policy);
916
+ assertRuntimeStateBinding(validated, this);
917
+ return validated;
918
+ }
919
+ async exportHandoff(input) {
920
+ assertExactKeys(input, ["logicalTimeMs", "sourceStateKey", "targetStateKey"], "context integrity handoff export");
921
+ const sourceStateKey = id(input.sourceStateKey, "sourceStateKey");
922
+ const targetStateKey = id(input.targetStateKey, "targetStateKey");
923
+ if (sourceStateKey === targetStateKey)
924
+ fail("context_integrity_handoff_target_invalid");
925
+ const logicalTimeMs = nonNegative(input.logicalTimeMs, "logicalTimeMs");
926
+ const sourceState = await this.getState(sourceStateKey);
927
+ if (!sourceState)
928
+ fail("context_integrity_handoff_source_missing");
929
+ if (logicalTimeMs < sourceState.logicalTimeHighWaterMs)
930
+ fail("context_integrity_handoff_time_rollback");
931
+ const body = freeze({
932
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
933
+ contentClass: "context_integrity_state",
934
+ controllerId: this.controllerId,
935
+ controllerVersion: this.controllerVersion,
936
+ implementationId: this.implementationId,
937
+ policyDigest: this.policyDigest,
938
+ analyzerId: this.analyzerId,
939
+ analyzerVersion: this.analyzerVersion,
940
+ analyzerImplementationDigest: this.analyzerImplementationDigest,
941
+ sourceStateKey,
942
+ sourceStateDigest: sourceState.stateDigest,
943
+ targetStateKey,
944
+ exportedAtLogicalMs: logicalTimeMs,
945
+ sourceState,
946
+ });
947
+ return freeze({
948
+ ...body,
949
+ handoffDigest: digestContextIntegrityJsonV1("handoff", body),
950
+ });
951
+ }
952
+ async importHandoff(input) {
953
+ assertExactKeys(input, ["handoff", "logicalTimeMs", "targetStateKey"], "context integrity handoff import");
954
+ const targetStateKey = id(input.targetStateKey, "targetStateKey");
955
+ const logicalTimeMs = nonNegative(input.logicalTimeMs, "logicalTimeMs");
956
+ const handoff = validateContextIntegrityHandoffV1(input.handoff, this.#policy);
957
+ if (handoff.controllerId !== this.controllerId ||
958
+ handoff.controllerVersion !== this.controllerVersion ||
959
+ handoff.implementationId !== this.implementationId ||
960
+ handoff.policyDigest !== this.policyDigest ||
961
+ handoff.analyzerId !== this.analyzerId ||
962
+ handoff.analyzerVersion !== this.analyzerVersion ||
963
+ handoff.analyzerImplementationDigest !==
964
+ this.analyzerImplementationDigest ||
965
+ handoff.targetStateKey !== targetStateKey)
966
+ fail("context_integrity_handoff_binding_invalid");
967
+ if (logicalTimeMs < handoff.exportedAtLogicalMs ||
968
+ logicalTimeMs < handoff.sourceState.logicalTimeHighWaterMs)
969
+ fail("context_integrity_handoff_time_rollback");
970
+ const existing = await this.getState(targetStateKey);
971
+ if (existing) {
972
+ if (existing.predecessorStateDigest === handoff.sourceStateDigest)
973
+ return existing;
974
+ fail("context_integrity_handoff_target_conflict");
975
+ }
976
+ const source = handoff.sourceState;
977
+ const restored = createContextIntegrityStateV1({
978
+ stateKey: targetStateKey,
979
+ controllerId: this.controllerId,
980
+ controllerVersion: this.controllerVersion,
981
+ implementationId: this.implementationId,
982
+ policy: this.#policy,
983
+ analyzer: this,
984
+ revision: 1,
985
+ logicalTimeHighWaterMs: logicalTimeMs,
986
+ stepCount: source.stepCount,
987
+ status: source.status,
988
+ degraded: source.degraded,
989
+ adverseStreak: source.adverseStreak,
990
+ recoveryStreak: source.recoveryStreak,
991
+ interventionCounts: source.interventionCounts,
992
+ heads: source.heads,
993
+ rollingWindow: source.rollingWindow,
994
+ predecessorStateDigest: source.stateDigest,
995
+ lastRequestDigest: null,
996
+ lastDecision: null,
997
+ });
998
+ if (await this.#store.save({ state: restored, expectedRevision: null }))
999
+ return restored;
1000
+ const raced = await this.getState(targetStateKey);
1001
+ if (raced?.predecessorStateDigest === handoff.sourceStateDigest)
1002
+ return raced;
1003
+ fail("context_integrity_handoff_target_conflict");
1004
+ }
1005
+ }
1006
+ export function validateContextIntegrityHandoffV1(input, policyValue) {
1007
+ assertExactKeys(input, handoffKeys, "context integrity handoff");
1008
+ const value = input;
1009
+ if (value.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1 ||
1010
+ value.contentClass !== "context_integrity_state")
1011
+ fail("context_integrity_handoff_format_invalid");
1012
+ const sourceState = validateContextIntegrityStateV1(value.sourceState, policyValue);
1013
+ const body = freeze({
1014
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
1015
+ contentClass: "context_integrity_state",
1016
+ controllerId: id(value.controllerId, "handoff.controllerId"),
1017
+ controllerVersion: positive(value.controllerVersion, "handoff.controllerVersion"),
1018
+ implementationId: id(value.implementationId, "handoff.implementationId"),
1019
+ policyDigest: sha(value.policyDigest, "handoff.policyDigest"),
1020
+ analyzerId: id(value.analyzerId, "handoff.analyzerId"),
1021
+ analyzerVersion: positive(value.analyzerVersion, "handoff.analyzerVersion"),
1022
+ analyzerImplementationDigest: sha(value.analyzerImplementationDigest, "handoff.analyzerImplementationDigest"),
1023
+ sourceStateKey: id(value.sourceStateKey, "handoff.sourceStateKey"),
1024
+ sourceStateDigest: sha(value.sourceStateDigest, "handoff.sourceStateDigest"),
1025
+ targetStateKey: id(value.targetStateKey, "handoff.targetStateKey"),
1026
+ exportedAtLogicalMs: nonNegative(value.exportedAtLogicalMs, "handoff.exportedAtLogicalMs"),
1027
+ sourceState,
1028
+ });
1029
+ if (body.sourceState.stateKey !== body.sourceStateKey ||
1030
+ body.sourceState.stateDigest !== body.sourceStateDigest ||
1031
+ body.sourceState.controllerId !== body.controllerId ||
1032
+ body.sourceState.controllerVersion !== body.controllerVersion ||
1033
+ body.sourceState.implementationId !== body.implementationId ||
1034
+ body.sourceState.policyDigest !== body.policyDigest ||
1035
+ body.sourceState.analyzerId !== body.analyzerId ||
1036
+ body.sourceState.analyzerVersion !== body.analyzerVersion ||
1037
+ body.sourceState.analyzerImplementationDigest !==
1038
+ body.analyzerImplementationDigest ||
1039
+ body.sourceStateKey === body.targetStateKey)
1040
+ fail("context_integrity_handoff_binding_invalid");
1041
+ const handoffDigest = digestContextIntegrityJsonV1("handoff", body);
1042
+ if (value.handoffDigest !== handoffDigest)
1043
+ fail("context_integrity_handoff_digest_invalid");
1044
+ return freeze({ ...body, handoffDigest });
1045
+ }
1046
+ export class InMemoryContextIntegrityStoreV1 {
1047
+ #states = new Map();
1048
+ #policy;
1049
+ constructor(policy) {
1050
+ this.#policy = validateContextIntegrityPolicyV1(policy);
1051
+ }
1052
+ async load(stateKeyValue) {
1053
+ const state = this.#states.get(id(stateKeyValue, "stateKey"));
1054
+ return state ? cloneJson(state) : null;
1055
+ }
1056
+ async save(input) {
1057
+ assertExactKeys(input, ["expectedRevision", "state"], "context integrity store save");
1058
+ const state = validateContextIntegrityStateV1(input.state, this.#policy);
1059
+ const current = this.#states.get(state.stateKey);
1060
+ if (input.expectedRevision === null
1061
+ ? current !== undefined || state.revision !== 1
1062
+ : !current ||
1063
+ current.revision !== input.expectedRevision ||
1064
+ state.revision !== input.expectedRevision + 1)
1065
+ return false;
1066
+ this.#states.set(state.stateKey, cloneJson(state));
1067
+ return true;
1068
+ }
1069
+ }
1070
+ export function projectContextIntegrityRoleV1(stateValue, policyValue) {
1071
+ const state = validateContextIntegrityStateV1(stateValue, policyValue);
1072
+ const latest = state.rollingWindow.at(-1);
1073
+ const uncertaintyBps = latest?.maximumUncertaintyBps ?? 10_000;
1074
+ const riskBps = latest?.maximumRiskBps ?? 10_000;
1075
+ const roleStatus = state.status === "denied"
1076
+ ? "denied"
1077
+ : state.status === "paused"
1078
+ ? "paused"
1079
+ : state.degraded
1080
+ ? "realignment_required"
1081
+ : state.status === "active"
1082
+ ? "active"
1083
+ : "unavailable";
1084
+ const body = freeze({
1085
+ roleStatus,
1086
+ degraded: state.degraded,
1087
+ coherenceBps: Math.max(0, 10_000 - riskBps),
1088
+ uncertaintyBps,
1089
+ });
1090
+ return freeze({
1091
+ ...body,
1092
+ projectionDigest: digestContextIntegrityJsonV1("projection", body),
1093
+ });
1094
+ }
1095
+ export function contextIntegrityHeadKeyV1(input) {
1096
+ id(input.sourceId, "head.sourceId");
1097
+ const digest = digestContextIntegrityJsonV1("head", {
1098
+ analyzerId: id(input.analyzerId, "head.analyzerId"),
1099
+ itemId: id(input.itemId, "head.itemId"),
1100
+ });
1101
+ return `context-integrity-head.${digest.slice(7)}`;
1102
+ }
1103
+ function normalizePolicy(input) {
1104
+ assertExactKeys(input, policyKeys, "context integrity policy");
1105
+ if (input.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
1106
+ fail("context_integrity_policy_schema_invalid");
1107
+ const thresholds = normalizeThresholds(input.thresholds);
1108
+ const limits = normalizeLimits(input.limits);
1109
+ const trustedSourceZones = input.trustedSourceZones.map(sourceZone);
1110
+ sortedUnique(trustedSourceZones, "trustedSourceZones");
1111
+ const allowedFilterBindingDigests = digests(input.allowedFilterBindingDigests, "allowedFilterBindingDigests", 32);
1112
+ const minimumCorroborationGroups = bounded(input.minimumCorroborationGroups, "minimumCorroborationGroups", limits.maximumCorroborationGroupsPerItem, 0);
1113
+ return freeze({
1114
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
1115
+ policyId: id(input.policyId, "policyId"),
1116
+ policyVersion: positive(input.policyVersion, "policyVersion"),
1117
+ parentPolicyDigest: nullableDigest(input.parentPolicyDigest, "parentPolicyDigest"),
1118
+ trustedSourceZones: freeze(trustedSourceZones),
1119
+ allowedFilterBindingDigests,
1120
+ thresholds,
1121
+ minimumCorroborationGroups,
1122
+ adverseSignalsToPause: bounded(input.adverseSignalsToPause, "adverseSignalsToPause", 10_000, 1),
1123
+ recoverySignalsRequired: bounded(input.recoverySignalsRequired, "recoverySignalsRequired", 10_000, 1),
1124
+ allowEmptyAfterIsolation: boolean(input.allowEmptyAfterIsolation, "allowEmptyAfterIsolation"),
1125
+ limits,
1126
+ });
1127
+ }
1128
+ function normalizeThresholds(input) {
1129
+ assertExactKeys(input, thresholdKeys, "context integrity thresholds");
1130
+ const value = freeze({
1131
+ cautionRiskBps: bps(input.cautionRiskBps, "cautionRiskBps"),
1132
+ quarantineRiskBps: bps(input.quarantineRiskBps, "quarantineRiskBps"),
1133
+ denyRiskBps: bps(input.denyRiskBps, "denyRiskBps"),
1134
+ maximumUncertaintyBps: bps(input.maximumUncertaintyBps, "maximumUncertaintyBps"),
1135
+ contradictionRiskBps: bps(input.contradictionRiskBps, "contradictionRiskBps"),
1136
+ });
1137
+ if (value.cautionRiskBps >= value.quarantineRiskBps ||
1138
+ value.quarantineRiskBps >= value.denyRiskBps)
1139
+ fail("context_integrity_threshold_order_invalid");
1140
+ return value;
1141
+ }
1142
+ function normalizeLimits(input) {
1143
+ assertExactKeys(input, limitKeys, "context integrity limits");
1144
+ return freeze({
1145
+ maximumItemsPerRequest: bounded(input.maximumItemsPerRequest, "maximumItemsPerRequest", 256, 1),
1146
+ maximumRetainedHeads: bounded(input.maximumRetainedHeads, "maximumRetainedHeads", 65_536, 1),
1147
+ rollingWindowAssessments: bounded(input.rollingWindowAssessments, "rollingWindowAssessments", 1_024, 1),
1148
+ maximumReasonCodesPerAssessment: bounded(input.maximumReasonCodesPerAssessment, "maximumReasonCodesPerAssessment", 32, 1),
1149
+ maximumThreatKindsPerAssessment: bounded(input.maximumThreatKindsPerAssessment, "maximumThreatKindsPerAssessment", 32, 1),
1150
+ maximumEvidenceDigestsPerAssessment: bounded(input.maximumEvidenceDigestsPerAssessment, "maximumEvidenceDigestsPerAssessment", 32, 1),
1151
+ maximumCorroborationGroupsPerItem: bounded(input.maximumCorroborationGroupsPerItem, "maximumCorroborationGroupsPerItem", 32, 1),
1152
+ maximumSteps: bounded(input.maximumSteps, "maximumSteps", 1_000_000, 1),
1153
+ maximumAssessmentTtlMs: bounded(input.maximumAssessmentTtlMs, "maximumAssessmentTtlMs", 86_400_000, 1),
1154
+ maximumDecisionTtlMs: bounded(input.maximumDecisionTtlMs, "maximumDecisionTtlMs", 86_400_000, 1),
1155
+ maximumCommitAttempts: bounded(input.maximumCommitAttempts, "maximumCommitAttempts", 16, 1),
1156
+ });
1157
+ }
1158
+ function normalizeScope(input) {
1159
+ assertExactKeys(input, scopeKeys, "context integrity scope");
1160
+ return freeze({
1161
+ tenantId: id(input.tenantId, "scope.tenantId"),
1162
+ sessionId: id(input.sessionId, "scope.sessionId"),
1163
+ agentId: id(input.agentId, "scope.agentId"),
1164
+ objectiveId: id(input.objectiveId, "scope.objectiveId"),
1165
+ });
1166
+ }
1167
+ function normalizeAssessments(input, limits) {
1168
+ if (!Array.isArray(input) || input.length > limits.maximumItemsPerRequest)
1169
+ fail("context_integrity_assessments_invalid");
1170
+ return freeze(input.map((value) => {
1171
+ const assessment = validateContextIntegrityAssessmentV1(value);
1172
+ if (assessment.reasonCodes.length >
1173
+ limits.maximumReasonCodesPerAssessment ||
1174
+ assessment.threatKinds.length >
1175
+ limits.maximumThreatKindsPerAssessment ||
1176
+ assessment.evidenceDigests.length >
1177
+ limits.maximumEvidenceDigestsPerAssessment ||
1178
+ assessment.expiresAtLogicalMs - assessment.assessedAtLogicalMs >
1179
+ limits.maximumAssessmentTtlMs)
1180
+ fail("context_integrity_assessment_capacity_exceeded");
1181
+ return assessment;
1182
+ }));
1183
+ }
1184
+ function normalizeContents(input, request) {
1185
+ if (!Array.isArray(input) || input.length !== request.items.length)
1186
+ fail("context_integrity_content_coverage_invalid");
1187
+ const contents = input.map(validateContextIntegrityEphemeralContentV1);
1188
+ assertUnique(contents.map(({ itemId }) => itemId), "context integrity content IDs");
1189
+ const byId = new Map(contents.map((content) => [content.itemId, content]));
1190
+ for (const item of request.items) {
1191
+ const content = byId.get(item.itemId);
1192
+ if (!content || content.contentDigest !== item.contentDigest)
1193
+ fail("context_integrity_content_binding_invalid");
1194
+ }
1195
+ return byId;
1196
+ }
1197
+ function normalizeHeads(input) {
1198
+ if (!Array.isArray(input) || input.length > 65_536)
1199
+ fail("context_integrity_heads_invalid");
1200
+ const heads = input.map((head) => {
1201
+ assertExactKeys(head, headKeys, "context integrity head");
1202
+ if (head.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
1203
+ fail("context_integrity_head_schema_invalid");
1204
+ const normalized = freeze({
1205
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
1206
+ headKey: id(head.headKey, "headKey"),
1207
+ itemId: id(head.itemId, "head.itemId"),
1208
+ sourceId: id(head.sourceId, "head.sourceId"),
1209
+ sourceVersion: positive(head.sourceVersion, "head.sourceVersion"),
1210
+ sourceRevision: nonNegative(head.sourceRevision, "head.sourceRevision"),
1211
+ contentDigest: sha(head.contentDigest, "head.contentDigest"),
1212
+ analyzerId: id(head.analyzerId, "head.analyzerId"),
1213
+ analyzerRevision: nonNegative(head.analyzerRevision, "head.analyzerRevision"),
1214
+ analysisDigest: sha(head.analysisDigest, "head.analysisDigest"),
1215
+ assessmentDigest: sha(head.assessmentDigest, "head.assessmentDigest"),
1216
+ expiresAtLogicalMs: positive(head.expiresAtLogicalMs, "head.expiresAtLogicalMs"),
1217
+ });
1218
+ if (normalized.headKey !==
1219
+ contextIntegrityHeadKeyV1({
1220
+ itemId: normalized.itemId,
1221
+ sourceId: normalized.sourceId,
1222
+ analyzerId: normalized.analyzerId,
1223
+ }))
1224
+ fail("context_integrity_head_key_invalid");
1225
+ return normalized;
1226
+ });
1227
+ heads.sort(headOrder);
1228
+ sortedUnique(heads.map(({ headKey }) => headKey), "context integrity head keys");
1229
+ return freeze(heads);
1230
+ }
1231
+ function normalizeWindow(input) {
1232
+ if (!Array.isArray(input) || input.length > 1_024)
1233
+ fail("context_integrity_window_invalid");
1234
+ let priorTime = -1;
1235
+ return freeze(input.map((entry) => {
1236
+ assertExactKeys(entry, windowKeys, "context integrity window entry");
1237
+ if (entry.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
1238
+ fail("context_integrity_window_schema_invalid");
1239
+ const normalized = freeze({
1240
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
1241
+ requestDigest: sha(entry.requestDigest, "window.requestDigest"),
1242
+ maximumRiskBps: bps(entry.maximumRiskBps, "window.maximumRiskBps"),
1243
+ maximumUncertaintyBps: bps(entry.maximumUncertaintyBps, "window.maximumUncertaintyBps"),
1244
+ isolatedItems: nonNegative(entry.isolatedItems, "window.isolatedItems"),
1245
+ deniedItems: nonNegative(entry.deniedItems, "window.deniedItems"),
1246
+ evaluatedAtLogicalMs: nonNegative(entry.evaluatedAtLogicalMs, "window.evaluatedAtLogicalMs"),
1247
+ });
1248
+ if (normalized.evaluatedAtLogicalMs < priorTime)
1249
+ fail("context_integrity_window_time_rollback");
1250
+ priorTime = normalized.evaluatedAtLogicalMs;
1251
+ return normalized;
1252
+ }));
1253
+ }
1254
+ function normalizeInterventionCounts(input) {
1255
+ assertExactKeys(input, interventionKeys, "context integrity intervention counts");
1256
+ return freeze({
1257
+ restricted: nonNegative(input.restricted, "counts.restricted"),
1258
+ isolated: nonNegative(input.isolated, "counts.isolated"),
1259
+ corroborationRequired: nonNegative(input.corroborationRequired, "counts.corroborationRequired"),
1260
+ denied: nonNegative(input.denied, "counts.denied"),
1261
+ });
1262
+ }
1263
+ function normalizeDecision(input) {
1264
+ assertExactKeys(input, decisionKeys, "context integrity decision");
1265
+ const value = input;
1266
+ if (value.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
1267
+ fail("context_integrity_decision_schema_invalid");
1268
+ if (!Array.isArray(value.items) || value.items.length > 256)
1269
+ fail("context_integrity_decision_items_invalid");
1270
+ const items = value.items.map((item) => {
1271
+ assertExactKeys(item, itemDecisionKeys, "context integrity item decision");
1272
+ if (item.schemaVersion !== CONTEXT_INTEGRITY_SCHEMA_VERSION_V1)
1273
+ fail("context_integrity_item_decision_schema_invalid");
1274
+ return freeze({
1275
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
1276
+ itemId: id(item.itemId, "decision.itemId"),
1277
+ itemDigest: sha(item.itemDigest, "decision.itemDigest"),
1278
+ action: oneOf(item.action, itemActions, "decision.action"),
1279
+ riskBps: bps(item.riskBps, "decision.riskBps"),
1280
+ uncertaintyBps: bps(item.uncertaintyBps, "decision.uncertaintyBps"),
1281
+ reasonCodes: tokens(item.reasonCodes, "decision.reasonCodes", 64),
1282
+ assessmentDigest: nullableDigest(item.assessmentDigest, "decision.assessmentDigest"),
1283
+ });
1284
+ });
1285
+ assertUnique(items.map(({ itemId }) => itemId), "context integrity decision item IDs");
1286
+ const body = freeze({
1287
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
1288
+ controllerId: id(value.controllerId, "decision.controllerId"),
1289
+ controllerVersion: positive(value.controllerVersion, "decision.controllerVersion"),
1290
+ implementationId: id(value.implementationId, "decision.implementationId"),
1291
+ policyId: id(value.policyId, "decision.policyId"),
1292
+ policyVersion: positive(value.policyVersion, "decision.policyVersion"),
1293
+ policyDigest: sha(value.policyDigest, "decision.policyDigest"),
1294
+ analyzerId: id(value.analyzerId, "decision.analyzerId"),
1295
+ analyzerVersion: positive(value.analyzerVersion, "decision.analyzerVersion"),
1296
+ analyzerImplementationDigest: sha(value.analyzerImplementationDigest, "decision.analyzerImplementationDigest"),
1297
+ requestId: id(value.requestId, "decision.requestId"),
1298
+ requestDigest: sha(value.requestDigest, "decision.requestDigest"),
1299
+ evaluatedAtLogicalMs: nonNegative(value.evaluatedAtLogicalMs, "decision.evaluatedAtLogicalMs"),
1300
+ expiresAtLogicalMs: positive(value.expiresAtLogicalMs, "decision.expiresAtLogicalMs"),
1301
+ priorStateRevision: nonNegative(value.priorStateRevision, "decision.priorStateRevision"),
1302
+ committedStateRevision: positive(value.committedStateRevision, "decision.committedStateRevision"),
1303
+ disposition: oneOf(value.disposition, ["allow", "abstain", "deny"], "decision.disposition"),
1304
+ filterRequired: boolean(value.filterRequired, "decision.filterRequired"),
1305
+ stateStatus: stateStatus(value.stateStatus),
1306
+ degraded: boolean(value.degraded, "decision.degraded"),
1307
+ items: freeze(items),
1308
+ });
1309
+ const expectedFilterRequired = body.items.some(({ action }) => action === "isolate" || action === "require_corroboration");
1310
+ if (body.committedStateRevision !== body.priorStateRevision + 1 ||
1311
+ body.expiresAtLogicalMs <= body.evaluatedAtLogicalMs ||
1312
+ body.filterRequired !== expectedFilterRequired ||
1313
+ body.degraded !== (body.stateStatus !== "active") ||
1314
+ (body.items.some(({ action }) => action === "deny") &&
1315
+ body.disposition !== "deny") ||
1316
+ (body.disposition === "allow" &&
1317
+ (body.stateStatus === "paused" || body.stateStatus === "denied")))
1318
+ fail("context_integrity_decision_revision_invalid");
1319
+ const decisionDigest = digestContextIntegrityJsonV1("decision", body);
1320
+ const decisionId = `context-integrity-decision.${decisionDigest.slice(7)}`;
1321
+ if (value.decisionId !== decisionId ||
1322
+ value.decisionDigest !== decisionDigest)
1323
+ fail("context_integrity_decision_digest_invalid");
1324
+ return freeze({ ...body, decisionId, decisionDigest });
1325
+ }
1326
+ function decideItemAction(input) {
1327
+ const { item, assessment, policy, reasons } = input;
1328
+ if (assessment.disposition === "deny" ||
1329
+ assessment.riskBps >= policy.thresholds.denyRiskBps) {
1330
+ reasons.add("risk_denied");
1331
+ return "deny";
1332
+ }
1333
+ if (input.contradictory) {
1334
+ reasons.add("claim_contradiction");
1335
+ return assessment.riskBps >= policy.thresholds.contradictionRiskBps
1336
+ ? "isolate"
1337
+ : "require_corroboration";
1338
+ }
1339
+ if (item.claimKeyDigest !== null &&
1340
+ item.corroborationGroupIds.length < policy.minimumCorroborationGroups &&
1341
+ !policy.trustedSourceZones.includes(item.sourceZone)) {
1342
+ reasons.add("corroboration_insufficient");
1343
+ return "require_corroboration";
1344
+ }
1345
+ if (assessment.disposition === "quarantine" ||
1346
+ assessment.disposition === "unavailable" ||
1347
+ assessment.riskBps >= policy.thresholds.quarantineRiskBps ||
1348
+ assessment.uncertaintyBps > policy.thresholds.maximumUncertaintyBps) {
1349
+ reasons.add(assessment.uncertaintyBps > policy.thresholds.maximumUncertaintyBps
1350
+ ? "uncertainty_excessive"
1351
+ : "risk_quarantined");
1352
+ return "isolate";
1353
+ }
1354
+ if (assessment.disposition === "caution" ||
1355
+ assessment.riskBps >= policy.thresholds.cautionRiskBps) {
1356
+ reasons.add("risk_restricted");
1357
+ return "restrict";
1358
+ }
1359
+ reasons.add("context_admitted");
1360
+ return "admit";
1361
+ }
1362
+ function contradictoryClaimKeys(items) {
1363
+ const values = new Map();
1364
+ const groups = new Map();
1365
+ for (const item of items) {
1366
+ if (!item.claimKeyDigest || !item.claimValueDigest)
1367
+ continue;
1368
+ const claimValues = values.get(item.claimKeyDigest) ?? new Set();
1369
+ claimValues.add(item.claimValueDigest);
1370
+ values.set(item.claimKeyDigest, claimValues);
1371
+ const claimGroups = groups.get(item.claimKeyDigest) ?? new Set();
1372
+ for (const groupId of item.corroborationGroupIds)
1373
+ claimGroups.add(groupId);
1374
+ groups.set(item.claimKeyDigest, claimGroups);
1375
+ }
1376
+ return new Set([...values.entries()]
1377
+ .filter(([key, claimValues]) => claimValues.size > 1 && (groups.get(key)?.size ?? 0) > 1)
1378
+ .map(([key]) => key));
1379
+ }
1380
+ function headFrom(item, assessment) {
1381
+ return freeze({
1382
+ schemaVersion: CONTEXT_INTEGRITY_SCHEMA_VERSION_V1,
1383
+ headKey: contextIntegrityHeadKeyV1({
1384
+ itemId: item.itemId,
1385
+ sourceId: item.sourceId,
1386
+ analyzerId: assessment.analyzerId,
1387
+ }),
1388
+ itemId: item.itemId,
1389
+ sourceId: item.sourceId,
1390
+ sourceVersion: item.sourceVersion,
1391
+ sourceRevision: item.sourceRevision,
1392
+ contentDigest: item.contentDigest,
1393
+ analyzerId: assessment.analyzerId,
1394
+ analyzerRevision: assessment.analyzerRevision,
1395
+ analysisDigest: assessment.analysisDigest,
1396
+ assessmentDigest: assessment.assessmentDigest,
1397
+ expiresAtLogicalMs: item.expiresAtLogicalMs,
1398
+ });
1399
+ }
1400
+ function assertStateBindings(state, policy) {
1401
+ if (state.policyId !== policy.policy.policyId ||
1402
+ state.policyVersion !== policy.policy.policyVersion ||
1403
+ state.policyDigest !== policy.policyDigest)
1404
+ fail("context_integrity_policy_binding_changed");
1405
+ }
1406
+ function assertRuntimeStateBinding(state, runtime) {
1407
+ if (state.controllerId !== runtime.controllerId ||
1408
+ state.controllerVersion !== runtime.controllerVersion ||
1409
+ state.implementationId !== runtime.implementationId ||
1410
+ state.analyzerId !== runtime.analyzerId ||
1411
+ state.analyzerVersion !== runtime.analyzerVersion ||
1412
+ state.analyzerImplementationDigest !== runtime.analyzerImplementationDigest)
1413
+ fail("context_integrity_runtime_binding_changed");
1414
+ }
1415
+ function checkpoint(input) {
1416
+ return oneOf(input, checkpoints, "checkpoint");
1417
+ }
1418
+ function targetKind(input) {
1419
+ return oneOf(input, targetKinds, "targetKind");
1420
+ }
1421
+ function sourceZone(input) {
1422
+ return oneOf(input, CONTEXT_INTEGRITY_SOURCE_ZONES_V1, "sourceZone");
1423
+ }
1424
+ function memoryTier(input) {
1425
+ return oneOf(input, CONTEXT_INTEGRITY_MEMORY_TIERS_V1, "memoryTier");
1426
+ }
1427
+ function assessmentDisposition(input) {
1428
+ return oneOf(input, assessmentDispositions, "assessment disposition");
1429
+ }
1430
+ function stateStatus(input) {
1431
+ return oneOf(input, stateStatuses, "state status");
1432
+ }
1433
+ function id(input, label) {
1434
+ assertIdentifier(input, label);
1435
+ return input;
1436
+ }
1437
+ function sha(input, label) {
1438
+ assertDigest(input, label);
1439
+ return input;
1440
+ }
1441
+ function nullableDigest(input, label) {
1442
+ return input === null ? null : sha(input, label);
1443
+ }
1444
+ function positive(input, label) {
1445
+ assertSafeInteger(input, label, 1);
1446
+ return input;
1447
+ }
1448
+ function nonNegative(input, label) {
1449
+ assertSafeInteger(input, label, 0);
1450
+ return input;
1451
+ }
1452
+ function bps(input, label) {
1453
+ const value = nonNegative(input, label);
1454
+ if (value > 10_000)
1455
+ fail(`${label}_out_of_range`);
1456
+ return value;
1457
+ }
1458
+ function bounded(input, label, maximum, minimum) {
1459
+ assertSafeInteger(input, label, minimum);
1460
+ if (input > maximum)
1461
+ fail(`${label}_exceeds_hard_maximum`);
1462
+ return input;
1463
+ }
1464
+ function boolean(input, label) {
1465
+ if (typeof input !== "boolean")
1466
+ fail(`${label}_invalid`);
1467
+ return input;
1468
+ }
1469
+ function oneOf(input, values, label) {
1470
+ assertOneOf(input, values, label);
1471
+ return input;
1472
+ }
1473
+ function tokens(input, label, maximum) {
1474
+ if (!Array.isArray(input) || input.length > maximum)
1475
+ fail(`${label}_invalid`);
1476
+ const values = input.map((value, index) => id(value, `${label}[${index}]`));
1477
+ sortedUnique(values, label);
1478
+ return freeze(values);
1479
+ }
1480
+ function digests(input, label, maximum) {
1481
+ if (!Array.isArray(input) || input.length > maximum)
1482
+ fail(`${label}_invalid`);
1483
+ const values = input.map((value, index) => sha(value, `${label}[${index}]`));
1484
+ sortedUnique(values, label);
1485
+ return freeze(values);
1486
+ }
1487
+ function headOrder(left, right) {
1488
+ return compare(left.headKey, right.headKey);
1489
+ }
1490
+ function compare(left, right) {
1491
+ return left < right ? -1 : left > right ? 1 : 0;
1492
+ }
1493
+ function assertUnique(values, label) {
1494
+ if (new Set(values).size !== values.length)
1495
+ fail(`${label}_duplicated`);
1496
+ }
1497
+ function safeAdd(left, right, reason) {
1498
+ const result = left + right;
1499
+ if (!Number.isSafeInteger(result))
1500
+ fail(reason);
1501
+ return result;
1502
+ }
1503
+ function freeze(value) {
1504
+ return deepFreeze(value);
1505
+ }
1506
+ function cloneJson(value) {
1507
+ return freeze(JSON.parse(JSON.stringify(value)));
1508
+ }
1509
+ function fail(message) {
1510
+ throw new TypeError(message);
1511
+ }
1512
+ //# sourceMappingURL=context-integrity-runtime.js.map