@astrale-os/kernel-dsl 1.0.0-beta.2 → 1.0.0-beta.20

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 (307) hide show
  1. package/dist/v1/addressing/class-key.js +3 -3
  2. package/dist/v1/addressing/definition-ref.js +21 -37
  3. package/dist/v1/addressing/domain-dependency.d.ts +0 -6
  4. package/dist/v1/addressing/domain-dependency.js +1 -6
  5. package/dist/v1/addressing/key.d.ts +4 -1
  6. package/dist/v1/addressing/key.js +23 -3
  7. package/dist/v1/addressing/ordering.d.ts +2 -0
  8. package/dist/v1/addressing/ordering.js +4 -0
  9. package/dist/v1/addressing/patterns.d.ts +1 -1
  10. package/dist/v1/addressing/patterns.js +2 -6
  11. package/dist/v1/builder/callable/authoring.d.ts +11 -5
  12. package/dist/v1/builder/callable/authoring.js +2 -0
  13. package/dist/v1/builder/class/authoring.d.ts +94 -224
  14. package/dist/v1/builder/class/authoring.js +31 -33
  15. package/dist/v1/builder/class/handle.d.ts +27 -0
  16. package/dist/v1/builder/class/handle.js +1 -0
  17. package/dist/v1/builder/class/input.d.ts +159 -0
  18. package/dist/v1/builder/class/projection.d.ts +129 -0
  19. package/dist/v1/builder/class/projection.js +1 -0
  20. package/dist/v1/builder/class/property.d.ts +3 -9
  21. package/dist/v1/builder/class/property.js +1 -0
  22. package/dist/v1/builder/core/authoring.d.ts +1 -1
  23. package/dist/v1/builder/index.d.ts +5 -2
  24. package/dist/v1/builder/lowering/callable.js +1 -0
  25. package/dist/v1/builder/lowering/class.d.ts +9 -1
  26. package/dist/v1/builder/lowering/class.js +62 -17
  27. package/dist/v1/builder/lowering/policy.js +2 -0
  28. package/dist/v1/builder/lowering/property-keys.d.ts +27 -0
  29. package/dist/v1/builder/lowering/property-keys.js +108 -0
  30. package/dist/v1/builder/lowering/schema/compile.js +11 -6
  31. package/dist/v1/builder/lowering/schema/context.d.ts +9 -1
  32. package/dist/v1/builder/lowering/schema/context.js +36 -4
  33. package/dist/v1/builder/lowering/schema/lifetime.d.ts +11 -0
  34. package/dist/v1/builder/lowering/schema/lifetime.js +55 -0
  35. package/dist/v1/builder/lowering/value/path.d.ts +1 -1
  36. package/dist/v1/builder/lowering/value/path.js +2 -4
  37. package/dist/v1/builder/lowering/value/zod.js +1 -3
  38. package/dist/v1/builder/policy/authoring.d.ts +85 -5
  39. package/dist/v1/builder/policy/authoring.js +107 -68
  40. package/dist/v1/builder/schema/define.d.ts +0 -1
  41. package/dist/v1/builder/schema/diagnostic.d.ts +3 -2
  42. package/dist/v1/builder/schema/diagnostic.js +5 -10
  43. package/dist/v1/builder/schema/input.d.ts +1 -1
  44. package/dist/v1/builder/schema/projection/callable.d.ts +7 -5
  45. package/dist/v1/builder/schema/projection/class.d.ts +118 -15
  46. package/dist/v1/builder/schema/projection/core-input.d.ts +2 -1
  47. package/dist/v1/builder/schema/projection/identity.d.ts +2 -1
  48. package/dist/v1/builder/schema/projection/model.d.ts +4 -2
  49. package/dist/v1/builder/schema/projection/property.d.ts +1 -1
  50. package/dist/v1/builder/schema/projection/resolved-class.d.ts +2 -1
  51. package/dist/v1/builder/schema/projection.d.ts +1 -1
  52. package/dist/v1/builder/value/full-match.d.ts +0 -1
  53. package/dist/v1/builder/value/full-match.js +0 -1
  54. package/dist/v1/builder/value/path-metadata.d.ts +1 -1
  55. package/dist/v1/builder/value/path.d.ts +1 -1
  56. package/dist/v1/bundle/codec.js +11 -13
  57. package/dist/v1/bundle/diagnostic.d.ts +2 -0
  58. package/dist/v1/bundle/diagnostic.js +9 -7
  59. package/dist/v1/bundle/model.js +1 -1
  60. package/dist/v1/bundle/structure.js +4 -6
  61. package/dist/v1/compiled/admission/accept.js +4 -10
  62. package/dist/v1/compiled/admission/closure.js +2 -2
  63. package/dist/v1/compiled/admission/diagnostic.d.ts +1 -1
  64. package/dist/v1/compiled/admission/diagnostic.js +1 -3
  65. package/dist/v1/compiled/admission/revision.d.ts +9 -1
  66. package/dist/v1/compiled/admission/revision.js +6 -3
  67. package/dist/v1/compiled/admission/semantics/class.d.ts +4 -1
  68. package/dist/v1/compiled/admission/semantics/class.js +37 -12
  69. package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
  70. package/dist/v1/compiled/admission/semantics/core.js +56 -24
  71. package/dist/v1/compiled/admission/semantics/edge.d.ts +2 -4
  72. package/dist/v1/compiled/admission/semantics/edge.js +6 -65
  73. package/dist/v1/compiled/admission/semantics/policy/callable.js +0 -2
  74. package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +5 -20
  75. package/dist/v1/compiled/admission/semantics/policy/contracts.js +8 -21
  76. package/dist/v1/compiled/admission/semantics/policy/parity.js +40 -43
  77. package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +4 -1
  78. package/dist/v1/compiled/admission/semantics/policy/pattern.js +4 -16
  79. package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +2 -24
  80. package/dist/v1/compiled/admission/semantics/policy/typing.js +19 -201
  81. package/dist/v1/compiled/admission/wire/callable.js +11 -1
  82. package/dist/v1/compiled/admission/wire/class.js +73 -21
  83. package/dist/v1/compiled/admission/wire/policy.d.ts +4 -3
  84. package/dist/v1/compiled/admission/wire/policy.js +8 -7
  85. package/dist/v1/compiled/compiler/compile.js +8 -8
  86. package/dist/v1/compiled/diagnostic.js +2 -3
  87. package/dist/v1/compiled/loader/load.d.ts +3 -2
  88. package/dist/v1/compiled/loader/load.js +11 -45
  89. package/dist/v1/domain/create.js +5 -6
  90. package/dist/v1/domain/model/domain.d.ts +2 -7
  91. package/dist/v1/domain/model/input.d.ts +2 -1
  92. package/dist/v1/domain/namespace/member-collection.js +4 -6
  93. package/dist/v1/domain/projection/classes.js +4 -1
  94. package/dist/v1/domain/validation/create.d.ts +6 -3
  95. package/dist/v1/domain/validation/create.js +21 -69
  96. package/dist/v1/index.d.ts +2 -1
  97. package/dist/v1/language/.spec/schemas/draft-2020-12.schema.json +462 -0
  98. package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
  99. package/dist/v1/language/callable/admission.d.ts +15 -0
  100. package/dist/v1/language/callable/admission.js +43 -0
  101. package/dist/v1/language/callable/model/callable.d.ts +10 -0
  102. package/dist/v1/language/callable/resolved.d.ts +16 -3
  103. package/dist/v1/language/class/inheritance.d.ts +36 -5
  104. package/dist/v1/language/class/inheritance.js +87 -1
  105. package/dist/v1/language/class/lifetime.d.ts +50 -11
  106. package/dist/v1/language/class/lifetime.js +89 -20
  107. package/dist/v1/language/class/model/class.d.ts +45 -9
  108. package/dist/v1/language/class/model/edge.d.ts +31 -2
  109. package/dist/v1/language/class/model/property.d.ts +16 -7
  110. package/dist/v1/language/class/property-values.js +2 -4
  111. package/dist/v1/language/class/unique.d.ts +143 -0
  112. package/dist/v1/language/class/unique.js +264 -0
  113. package/dist/v1/language/core/facts.d.ts +85 -0
  114. package/dist/v1/language/core/facts.js +116 -0
  115. package/dist/v1/language/definition/metadata.d.ts +5 -0
  116. package/dist/v1/language/definition/metadata.js +7 -0
  117. package/dist/v1/language/freeze.d.ts +5 -0
  118. package/dist/v1/{schema/canonical → language}/freeze.js +4 -0
  119. package/dist/v1/language/index.d.ts +7 -2
  120. package/dist/v1/language/index.js +5 -1
  121. package/dist/v1/language/limits.d.ts +64 -0
  122. package/dist/v1/language/limits.js +60 -0
  123. package/dist/v1/language/policy/analysis/branches.d.ts +8 -0
  124. package/dist/v1/language/policy/analysis/branches.js +2 -1
  125. package/dist/v1/language/policy/analysis/budgets.d.ts +45 -12
  126. package/dist/v1/language/policy/analysis/budgets.js +133 -19
  127. package/dist/v1/language/policy/analysis/checks.js +3 -2
  128. package/dist/v1/language/policy/analysis/typing.d.ts +51 -0
  129. package/dist/v1/language/policy/analysis/typing.js +455 -0
  130. package/dist/v1/language/policy/model/policy.d.ts +49 -9
  131. package/dist/v1/language/policy/model/policy.js +14 -0
  132. package/dist/v1/language/policy/normalization/normalize.d.ts +6 -6
  133. package/dist/v1/language/policy/normalization/normalize.js +22 -21
  134. package/dist/v1/language/validation/diagnostic.d.ts +15 -1
  135. package/dist/v1/language/validation/diagnostic.js +21 -0
  136. package/dist/v1/language/validation/rule.d.ts +45 -0
  137. package/dist/v1/language/validation/rule.js +109 -0
  138. package/dist/v1/language/value/compile/fields.js +4 -8
  139. package/dist/v1/language/value/evaluate/program.d.ts +2 -1
  140. package/dist/v1/language/value/evaluate/program.js +2 -2
  141. package/dist/v1/language/value/evaluate/validate.d.ts +2 -2
  142. package/dist/v1/language/value/evaluate/validate.js +6 -2
  143. package/dist/v1/language/value/evaluate/validity.optimization.d.ts +14 -0
  144. package/dist/v1/language/value/evaluate/validity.optimization.js +342 -0
  145. package/dist/v1/language/value/inclusion/arrays.d.ts +3 -0
  146. package/dist/v1/language/value/inclusion/arrays.js +85 -0
  147. package/dist/v1/language/value/inclusion/assertions.d.ts +18 -0
  148. package/dist/v1/language/value/inclusion/assertions.js +29 -0
  149. package/dist/v1/language/value/inclusion/combinators.d.ts +3 -0
  150. package/dist/v1/language/value/inclusion/combinators.js +67 -0
  151. package/dist/v1/language/value/inclusion/equivalence.d.ts +4 -0
  152. package/dist/v1/language/value/inclusion/equivalence.js +74 -0
  153. package/dist/v1/language/value/inclusion/evidence.d.ts +34 -0
  154. package/dist/v1/language/value/inclusion/evidence.js +138 -0
  155. package/dist/v1/language/value/inclusion/includes.d.ts +17 -0
  156. package/dist/v1/language/value/inclusion/includes.js +25 -719
  157. package/dist/v1/language/value/inclusion/keywords.d.ts +5 -0
  158. package/dist/v1/language/value/inclusion/keywords.js +31 -0
  159. package/dist/v1/language/value/inclusion/kinds.d.ts +17 -0
  160. package/dist/v1/language/value/inclusion/kinds.js +57 -0
  161. package/dist/v1/language/value/inclusion/location.d.ts +24 -0
  162. package/dist/v1/language/value/inclusion/location.js +63 -0
  163. package/dist/v1/language/value/inclusion/numbers.d.ts +3 -0
  164. package/dist/v1/language/value/inclusion/numbers.js +41 -0
  165. package/dist/v1/language/value/inclusion/objects.d.ts +3 -0
  166. package/dist/v1/language/value/inclusion/objects.js +190 -0
  167. package/dist/v1/language/value/inclusion/strings.d.ts +3 -0
  168. package/dist/v1/language/value/inclusion/strings.js +29 -0
  169. package/dist/v1/language/value/inclusion/types.d.ts +3 -0
  170. package/dist/v1/language/value/inclusion/types.js +11 -0
  171. package/dist/v1/language/value/ordering.d.ts +14 -0
  172. package/dist/v1/language/value/ordering.js +86 -9
  173. package/dist/v1/language/value/profile/canonicalize.js +6 -5
  174. package/dist/v1/language/value/profile/json.validate.d.ts +3 -1
  175. package/dist/v1/language/value/profile/json.validate.js +3 -2
  176. package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
  177. package/dist/v1/language/value/profile/rules.js +17 -43
  178. package/dist/v1/language/value/profile/validate.js +1 -10
  179. package/dist/v1/language/value/profile/vocabulary.d.ts +35 -2
  180. package/dist/v1/language/value/profile/vocabulary.js +52 -5
  181. package/dist/v1/language/value/reference/closure.js +3 -4
  182. package/dist/v1/language/value/reference/recursion.js +2 -22
  183. package/dist/v1/language/value/reference/registry.index.d.ts +2 -0
  184. package/dist/v1/language/value/reference/registry.index.js +33 -16
  185. package/dist/v1/language/value/regexp/ast.js +6 -7
  186. package/dist/v1/language/value/regexp/compile.d.ts +5 -11
  187. package/dist/v1/language/value/regexp/compile.js +14 -12
  188. package/dist/v1/language/value/regexp/syntax.js +3 -2
  189. package/dist/v1/language/value/syntax/keywords.d.ts +3 -3
  190. package/dist/v1/language/value/syntax/keywords.js +4 -20
  191. package/dist/v1/language/value/syntax/node-path/validate.js +2 -3
  192. package/dist/v1/language/value/syntax/pointer.d.ts +2 -0
  193. package/dist/v1/language/value/syntax/pointer.js +5 -2
  194. package/dist/v1/language/value/syntax/walk.d.ts +2 -0
  195. package/dist/v1/language/value/syntax/walk.js +19 -20
  196. package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +2519 -0
  197. package/dist/v1/schema/admission/accept.js +3 -14
  198. package/dist/v1/schema/admission/callable.d.ts +21 -0
  199. package/dist/v1/schema/admission/callable.js +96 -0
  200. package/dist/v1/schema/analysis/class.js +33 -15
  201. package/dist/v1/schema/canonical/revision.js +4 -4
  202. package/dist/v1/schema/compatibility/api.d.ts +2 -1
  203. package/dist/v1/schema/compatibility/api.js +1 -0
  204. package/dist/v1/schema/compatibility/comparators/callables.js +1 -1
  205. package/dist/v1/schema/compatibility/comparators/classes.d.ts +9 -4
  206. package/dist/v1/schema/compatibility/comparators/classes.js +29 -8
  207. package/dist/v1/schema/compatibility/comparators/index.d.ts +1 -1
  208. package/dist/v1/schema/compatibility/comparators/members.js +1 -1
  209. package/dist/v1/schema/compatibility/comparators/values.js +2 -2
  210. package/dist/v1/schema/compatibility/coordinate.js +3 -3
  211. package/dist/v1/schema/compatibility/diff.js +2 -4
  212. package/dist/v1/schema/compatibility/extension.d.ts +11 -0
  213. package/dist/v1/schema/compatibility/extension.js +22 -0
  214. package/dist/v1/schema/compatibility/fields.d.ts +20 -4
  215. package/dist/v1/schema/compatibility/fields.js +13 -3
  216. package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
  217. package/dist/v1/schema/compatibility/model.d.ts +17 -5
  218. package/dist/v1/schema/compatibility/report.js +1 -1
  219. package/dist/v1/schema/compatibility/scope.d.ts +2 -0
  220. package/dist/v1/schema/compatibility/scope.js +4 -1
  221. package/dist/v1/schema/compatibility/structure/index.js +6 -4
  222. package/dist/v1/schema/compatibility/structure/requirements.js +57 -58
  223. package/dist/v1/schema/compatibility/versioning/index.js +1 -1
  224. package/dist/v1/schema/compatibility/versioning/surface.d.ts +1 -1
  225. package/dist/v1/schema/compatibility/versioning/surface.js +30 -2
  226. package/dist/v1/schema/compatibility/walk.d.ts +17 -0
  227. package/dist/v1/schema/compatibility/walk.js +41 -0
  228. package/dist/v1/schema/diagnostic.d.ts +17 -3
  229. package/dist/v1/schema/diagnostic.js +14 -11
  230. package/dist/v1/schema/index.d.ts +10 -1
  231. package/dist/v1/schema/index.js +4 -0
  232. package/dist/v1/schema/model/schema.d.ts +20 -1
  233. package/dist/v1/schema/model/schema.js +1 -1
  234. package/dist/v1/schema/normalization/domain.d.ts +2 -0
  235. package/dist/v1/schema/normalization/domain.js +29 -9
  236. package/dist/v1/schema/resolution/closure.js +2 -1
  237. package/dist/v1/schema/resolution/context.js +13 -13
  238. package/dist/v1/schema/resolution/domain.d.ts +5 -0
  239. package/dist/v1/schema/resolution/domain.js +2 -2
  240. package/dist/v1/schema/resolution/origins.js +3 -2
  241. package/dist/v1/schema/rule.d.ts +26 -0
  242. package/dist/v1/schema/rule.js +440 -0
  243. package/dist/v1/schema/validation/callable.d.ts +35 -2
  244. package/dist/v1/schema/validation/callable.js +65 -9
  245. package/dist/v1/schema/validation/class.d.ts +6 -2
  246. package/dist/v1/schema/validation/class.js +127 -104
  247. package/dist/v1/schema/validation/core.js +90 -168
  248. package/dist/v1/schema/validation/domain.js +4 -13
  249. package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
  250. package/dist/v1/schema/validation/domain.json-schema.js +197 -0
  251. package/dist/v1/schema/validation/domain.route.d.ts +6 -1
  252. package/dist/v1/schema/validation/domain.route.js +18 -0
  253. package/dist/v1/schema/validation/domain.structure.d.ts +7780 -0
  254. package/dist/v1/schema/validation/domain.structure.js +398 -147
  255. package/dist/v1/schema/validation/json.json-schema.d.ts +40 -0
  256. package/dist/v1/schema/validation/json.json-schema.js +46 -0
  257. package/dist/v1/schema/validation/policy/budgets.d.ts +33 -2
  258. package/dist/v1/schema/validation/policy/budgets.js +87 -121
  259. package/dist/v1/schema/validation/policy/context.d.ts +6 -5
  260. package/dist/v1/schema/validation/policy/context.js +7 -10
  261. package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
  262. package/dist/v1/schema/validation/policy/objects.js +6 -14
  263. package/dist/v1/schema/validation/policy/references.js +11 -27
  264. package/dist/v1/schema/validation/policy/typing.d.ts +3 -18
  265. package/dist/v1/schema/validation/policy/typing.js +22 -356
  266. package/dist/v1/schema/validation/policy/uses.d.ts +40 -3
  267. package/dist/v1/schema/validation/policy/uses.js +66 -89
  268. package/dist/v1/schema/validation/policy/validate.js +5 -5
  269. package/dist/v1/schema/validation/value-api.d.ts +22 -0
  270. package/dist/v1/schema/validation/value-api.js +34 -1
  271. package/dist/v1/schema/validation/value.d.ts +3 -0
  272. package/dist/v1/schema/validation/value.js +9 -17
  273. package/dist/v1/schema/validation/value.json-schema.d.ts +49 -0
  274. package/dist/v1/schema/validation/value.json-schema.js +137 -0
  275. package/dist/v1/schema/validation/view.js +4 -8
  276. package/dist/value/canonical.d.ts +6 -0
  277. package/dist/value/canonical.js +36 -0
  278. package/dist/value/decode.d.ts +7 -0
  279. package/dist/value/decode.js +159 -9
  280. package/dist/value/index.d.ts +1 -1
  281. package/dist/value/json.d.ts +2 -2
  282. package/dist/value/json.js +2 -2
  283. package/dist/value/types.d.ts +6 -0
  284. package/dist/value/unicode.d.ts +2 -1
  285. package/dist/value/unicode.js +2 -0
  286. package/package.json +8 -1
  287. package/dist/v1/builder/lowering/core-properties.d.ts +0 -10
  288. package/dist/v1/builder/lowering/core-properties.js +0 -76
  289. package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
  290. package/dist/v1/compiled/admission/semantics/cardinality.js +0 -113
  291. package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
  292. package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
  293. package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
  294. package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
  295. package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
  296. package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
  297. package/dist/v1/language/class/index.d.ts +0 -8
  298. package/dist/v1/language/class/index.js +0 -1
  299. package/dist/v1/language/core/index.d.ts +0 -2
  300. package/dist/v1/language/value/index.d.ts +0 -11
  301. package/dist/v1/language/value/index.js +0 -8
  302. package/dist/v1/schema/canonical/domain.d.ts +0 -3
  303. package/dist/v1/schema/canonical/domain.digest.d.ts +0 -3
  304. package/dist/v1/schema/canonical/domain.digest.js +0 -5
  305. package/dist/v1/schema/canonical/domain.js +0 -5
  306. package/dist/v1/schema/canonical/freeze.d.ts +0 -1
  307. /package/dist/v1/{language/core/index.js → builder/class/input.js} +0 -0
@@ -0,0 +1,455 @@
1
+ import { Key } from '../../../addressing/index.js';
2
+ import { definitionRefIndex } from '../../../addressing/ordering.js';
3
+ import { classSatisfies, isGraphRoot } from '../../class/inheritance.js';
4
+ import { limits } from '../../limits.js';
5
+ import { branchesOf, branchProduct, capBranches, targetMode, termKey, UnionFind, } from './branches.js';
6
+ import { admittedCheckClasses } from './checks.js';
7
+ export class PolicyTyping {
8
+ scope;
9
+ // Expanded branches of each named Policy, cached by node identity. A Policy's expansion is reused
10
+ // across every composition path that reaches it (and across every use site and object contract,
11
+ // none of which the expansion depends on), so a shared-child composition DAG is expanded in work
12
+ // linear in the number of Policies instead of enumerating every path. The expansion result is
13
+ // independent of the reaching path up to the opaque term-namespace labels, which only ever
14
+ // disambiguate variables within one branch and leave targetMode and branch typing unchanged.
15
+ // Two occurrences of one Policy in a branch share labels only when a Policy reaches it by two
16
+ // paths; for that to merge distinct variables, the Policy expands deeper than
17
+ // `limits.policy.patternDepth`.
18
+ #expansions = new Map();
19
+ #index;
20
+ constructor(scope) {
21
+ this.scope = scope;
22
+ }
23
+ /** The normalized branches of a named Policy, `undefined` when it does not expand. */
24
+ expandedBranches(name, namespace) {
25
+ return this.#expandedBranches(name, new Set(), namespace);
26
+ }
27
+ policyAccepts(name, object) {
28
+ return this.#policyBranchTyping(name, object)?.every(Boolean) ?? false;
29
+ }
30
+ /** Whether the Policy accepts every concrete source and target pair the Edge Class accepts. */
31
+ policyAcceptsEdgeClass(name, declaration) {
32
+ const endpoints = endpointPair(declaration);
33
+ const sources = this.#concreteEndpointClasses(endpoints[0].accepts);
34
+ const targets = this.#concreteEndpointClasses(endpoints[1].accepts);
35
+ return sources.every((source) => targets.every((target) => this.#policyAcceptsEdge(name, { kind: 'exact', ref: source }, { kind: 'exact', ref: target })));
36
+ }
37
+ /**
38
+ * How a check of the Policy types against each contract of its object, `undefined` when the
39
+ * Policy does not expand or one of its branches is typed for no contract.
40
+ */
41
+ checkLeafClasses(name, contracts) {
42
+ const typings = new Map(contracts.map((contract) => [
43
+ contract.kind === 'exact' ? Key.of(contract.ref) : 'default',
44
+ this.#policyBranchTyping(name, contract),
45
+ ]));
46
+ const admitted = admittedCheckClasses(typings);
47
+ return admitted === undefined ? undefined : { accepted: [...typings.keys()], admitted };
48
+ }
49
+ endpointsOverlap(left, right) {
50
+ const seed = [{ kind: 'open', requirements: [] }];
51
+ const afterLeft = this.#applyEndpoint(seed, left);
52
+ return this.#applyEndpoint(afterLeft, right).length > 0;
53
+ }
54
+ branchIsTyped(branch, use) {
55
+ if (targetMode(branch) !== use.kind)
56
+ return false;
57
+ const alternatives = edgeAlternatives(branch.edges, this);
58
+ return alternatives.some((variants) => this.#constraintsAreSatisfiable(branch, variants, use));
59
+ }
60
+ /** Whether each normalized branch of the Policy is typed for an object of this contract. */
61
+ #policyBranchTyping(name, object) {
62
+ const branches = this.#expandedBranches(name, new Set(), `$use:${name}`);
63
+ const use = { kind: 'object', object };
64
+ return branches?.map((branch) => this.branchIsTyped(branch, use));
65
+ }
66
+ #policyAcceptsEdge(name, source, target) {
67
+ const branches = this.#expandedBranches(name, new Set(), `$edge-use:${name}`);
68
+ const use = { kind: 'edge', source, target };
69
+ return branches !== undefined && branches.every((branch) => this.branchIsTyped(branch, use));
70
+ }
71
+ #concreteEndpointClasses(accepts) {
72
+ const { concrete } = this.#nodeClassIndex();
73
+ return this.#satisfyingOneOf(accepts).filter((ref) => concrete.has(definitionRefIndex(ref)));
74
+ }
75
+ #nodeClassIndex() {
76
+ this.#index ??= nodeClassIndex(this.scope);
77
+ return this.#index;
78
+ }
79
+ #expandedBranches(name, visiting, namespace) {
80
+ if (visiting.has(name))
81
+ return undefined;
82
+ const cached = this.#expansions.get(name);
83
+ if (cached !== undefined || this.#expansions.has(name))
84
+ return cached;
85
+ const expanded = this.#expandDeclaration(name, visiting, namespace);
86
+ this.#expansions.set(name, expanded);
87
+ return expanded;
88
+ }
89
+ #expandDeclaration(name, visiting, namespace) {
90
+ const declaration = this.scope.normalized.get(name);
91
+ if (declaration === undefined)
92
+ return undefined;
93
+ if ('match' in declaration)
94
+ return branchesOf(declaration.match, namespace);
95
+ const nested = new Set(visiting);
96
+ nested.add(name);
97
+ const refs = 'allOf' in declaration ? declaration.allOf : declaration.anyOf;
98
+ const children = [];
99
+ for (const [index, ref] of refs.entries()) {
100
+ if (!this.scope.isLocalPolicy(ref))
101
+ return undefined;
102
+ const expanded = this.#expandedBranches(ref.name, nested, `${namespace}/${index}:${ref.name}`);
103
+ if (expanded === undefined)
104
+ return undefined;
105
+ children.push(expanded);
106
+ }
107
+ return 'allOf' in declaration ? branchProduct(children) : capBranches(children.flat());
108
+ }
109
+ #constraintsAreSatisfiable(branch, variants, use) {
110
+ const terms = new Set(use.kind === 'object' ? ['subject', 'object'] : ['subject', 'source', 'target']);
111
+ for (const key of branch.variables.keys())
112
+ terms.add(key);
113
+ for (const key of branch.terms.keys())
114
+ terms.add(key);
115
+ for (const edge of branch.edges) {
116
+ terms.add(termKey(edge.pattern.source, edge.namespace));
117
+ terms.add(termKey(edge.pattern.target, edge.namespace));
118
+ }
119
+ const union = new UnionFind(terms);
120
+ for (const [left, right] of branch.equalities)
121
+ union.join(left, right);
122
+ for (const variant of variants) {
123
+ for (const [left, right] of variant.equalities)
124
+ union.join(left, right);
125
+ }
126
+ const constraints = new Map();
127
+ for (const variant of variants) {
128
+ for (const [term, accepts] of variant.constraints) {
129
+ const root = union.find(term);
130
+ const values = constraints.get(root) ?? [];
131
+ values.push(accepts);
132
+ constraints.set(root, values);
133
+ }
134
+ }
135
+ const groups = new Map();
136
+ for (const term of terms) {
137
+ const root = union.find(term);
138
+ const members = groups.get(root) ?? [];
139
+ members.push(term);
140
+ groups.set(root, members);
141
+ }
142
+ for (const [root, members] of groups) {
143
+ const endpointConstraints = constraints.get(root) ?? [];
144
+ let candidates = [{ kind: 'open', requirements: [] }];
145
+ for (const member of members) {
146
+ candidates = this.#applyInitial(candidates, member, branch, use);
147
+ if (candidates.length === 0)
148
+ return false;
149
+ }
150
+ for (const endpoint of endpointConstraints) {
151
+ candidates = this.#applyEndpoint(candidates, endpoint);
152
+ if (candidates.length === 0)
153
+ return false;
154
+ }
155
+ }
156
+ return true;
157
+ }
158
+ #applyInitial(candidates, term, branch, use) {
159
+ if (term === 'subject')
160
+ return this.#applyAnyNodeClass(candidates);
161
+ const contract = targetContract(term, use);
162
+ if (contract !== undefined) {
163
+ if (contract.kind === 'exact')
164
+ return this.#applyExact(candidates, contract.ref);
165
+ if (contract.kind === 'default') {
166
+ return this.#applyAnyNodeClass(candidates).filter((candidate) => candidate.kind !== 'exact' || this.#isNodeClass(candidate.ref));
167
+ }
168
+ return candidates;
169
+ }
170
+ const referenced = branch.terms.get(term);
171
+ if (referenced?.kind === 'ref') {
172
+ const contract = this.scope.referenceContract(referenced.ref);
173
+ return contract?.kind === 'exact' ? this.#applyExact(candidates, contract.ref) : [];
174
+ }
175
+ const selector = branch.variables.get(term);
176
+ if (selector === undefined)
177
+ return [];
178
+ if (selector.kind === 'exact')
179
+ return this.#applyExact(candidates, selector.class);
180
+ if (selector.kind === 'any')
181
+ return candidates;
182
+ return this.#applyRequirement(candidates, selector.class);
183
+ }
184
+ #applyExact(candidates, exact) {
185
+ const result = [];
186
+ for (const candidate of candidates) {
187
+ if (candidate.kind === 'exact') {
188
+ if (definitionRefIndex(candidate.ref) === definitionRefIndex(exact))
189
+ result.push(candidate);
190
+ }
191
+ else if (candidate.kind === 'node') {
192
+ if (this.#isNodeClass(exact) && this.#satisfiesLists(exact, candidate.lists)) {
193
+ result.push({ kind: 'exact', ref: exact });
194
+ }
195
+ }
196
+ else if (candidate.requirements.every((required) => this.#classExtends(exact, required))) {
197
+ result.push({ kind: 'exact', ref: exact });
198
+ }
199
+ }
200
+ return uniqueBy(result, candidateKey);
201
+ }
202
+ #applyAnyNodeClass(candidates) {
203
+ return uniqueBy(candidates.flatMap((candidate) => candidate.kind === 'exact' ? [candidate] : this.#nodeCandidates(candidate)), candidateKey);
204
+ }
205
+ #applyRequirement(candidates, required) {
206
+ const result = [];
207
+ for (const candidate of candidates) {
208
+ if (candidate.kind === 'exact') {
209
+ if (this.#classExtends(candidate.ref, required))
210
+ result.push(candidate);
211
+ }
212
+ else if (candidate.kind === 'node') {
213
+ result.push(...this.#inhabited([...candidate.lists, [required]]));
214
+ }
215
+ else {
216
+ result.push({
217
+ kind: 'open',
218
+ requirements: uniqueBy([...candidate.requirements, required], definitionRefIndex),
219
+ });
220
+ }
221
+ }
222
+ return uniqueBy(result, candidateKey);
223
+ }
224
+ #applyEndpoint(candidates, accepts) {
225
+ const result = [];
226
+ for (const candidate of candidates) {
227
+ if (candidate.kind === 'exact') {
228
+ if (this.#classSatisfiesEndpoint(candidate.ref, accepts))
229
+ result.push(candidate);
230
+ continue;
231
+ }
232
+ if (candidate.kind === 'node') {
233
+ if (accepts.length > 0)
234
+ result.push(...this.#inhabited([...candidate.lists, accepts]));
235
+ continue;
236
+ }
237
+ for (const accept of accepts) {
238
+ result.push({
239
+ kind: 'open',
240
+ requirements: uniqueBy([...candidate.requirements, accept], definitionRefIndex),
241
+ });
242
+ }
243
+ }
244
+ return uniqueBy(result, candidateKey);
245
+ }
246
+ #classSatisfiesEndpoint(candidate, accepts) {
247
+ return accepts.some((accept) => this.#classExtends(candidate, accept));
248
+ }
249
+ /** Whether `candidate` is the `required` Class or a same-kind descendant. */
250
+ #classExtends(candidate, required) {
251
+ const resolve = (ref) => this.scope.resolveClass(ref);
252
+ const actual = resolve(candidate);
253
+ const target = resolve(required);
254
+ return actual !== undefined && target !== undefined && classSatisfies(actual, target, resolve);
255
+ }
256
+ /**
257
+ * The Node Classes of the closure that satisfy one Class of `accepts`, in closure order: those
258
+ * `#classSatisfiesEndpoint` accepts, read from the index rather than tested one by one.
259
+ */
260
+ #satisfyingOneOf(accepts) {
261
+ const index = this.#nodeClassIndex();
262
+ const positions = new Set();
263
+ for (const accept of accepts) {
264
+ const required = this.scope.resolveClass(accept);
265
+ if (required?.kind !== 'node')
266
+ continue;
267
+ if (isGraphRoot(required))
268
+ return index.nodeClasses;
269
+ for (const position of index.satisfying.get(definitionRefIndex(required.ref)) ?? []) {
270
+ positions.add(position);
271
+ }
272
+ }
273
+ return [...positions].sort((left, right) => left - right).map((at) => index.nodeClasses[at]);
274
+ }
275
+ #satisfiesLists(ref, lists) {
276
+ return lists.every((accepts) => this.#classSatisfiesEndpoint(ref, accepts));
277
+ }
278
+ #isNodeClass(ref) {
279
+ return this.#nodeClassIndex().nodes.has(definitionRefIndex(ref));
280
+ }
281
+ /** The Node Classes an open or `node` candidate can be. */
282
+ #nodeCandidates(candidate) {
283
+ return candidate.kind === 'node'
284
+ ? [candidate]
285
+ : this.#inhabited(candidate.requirements.map((required) => [required]));
286
+ }
287
+ /**
288
+ * The `node` candidate of these lists when some Node Class of the closure satisfies them, so that
289
+ * an empty one is dropped where its expansion would have been empty. A witness is almost always a
290
+ * Class the lists name; only when none is does the search read the Classes that satisfy the
291
+ * narrowest list, every witness being one of them.
292
+ */
293
+ #inhabited(lists) {
294
+ const fits = (ref) => this.#isNodeClass(ref) && this.#satisfiesLists(ref, lists);
295
+ const inhabited = lists.some((accepts) => accepts.some(fits)) ||
296
+ (lists.length === 0
297
+ ? this.scope.allNodeClasses
298
+ : lists
299
+ .map((accepts) => this.#satisfyingOneOf(accepts))
300
+ .reduce((narrowest, next) => (next.length < narrowest.length ? next : narrowest))).some(fits);
301
+ return inhabited ? [{ kind: 'node', lists }] : [];
302
+ }
303
+ }
304
+ /**
305
+ * Index each Node Class of the closure under every Class its ancestry reaches, walked as
306
+ * `classSatisfies` walks it: the Class itself, then each declared parent that resolves to a Node
307
+ * Class. A Class then satisfies a non-root Node Class exactly when it is indexed under it.
308
+ * `classSatisfies` compares origin and name; every ClassRef has kind `class`, so the definition
309
+ * index of a ref keys it as that comparison does.
310
+ */
311
+ function nodeClassIndex(scope) {
312
+ const nodeClasses = [];
313
+ const satisfying = new Map();
314
+ for (const ref of scope.allNodeClasses) {
315
+ const actual = scope.resolveClass(ref);
316
+ if (actual?.kind !== 'node')
317
+ continue;
318
+ const position = nodeClasses.push(ref) - 1;
319
+ for (const key of ancestryKeys(actual, scope)) {
320
+ const positions = satisfying.get(key);
321
+ if (positions === undefined)
322
+ satisfying.set(key, [position]);
323
+ else
324
+ positions.push(position);
325
+ }
326
+ }
327
+ return {
328
+ nodeClasses,
329
+ nodes: new Set(nodeClasses.map(definitionRefIndex)),
330
+ concrete: new Set(scope.concreteNodeClasses.map(definitionRefIndex)),
331
+ satisfying,
332
+ };
333
+ }
334
+ /** The keys of the Node Classes a Node Class's ancestry reaches, itself included. */
335
+ function ancestryKeys(actual, scope) {
336
+ const seen = new Set();
337
+ const keys = new Set();
338
+ const pending = [actual];
339
+ for (let value = pending.pop(); value !== undefined; value = pending.pop()) {
340
+ if (seen.has(value))
341
+ continue;
342
+ seen.add(value);
343
+ keys.add(definitionRefIndex(value.ref));
344
+ for (const parent of value.extends) {
345
+ const resolved = scope.resolveClass(parent);
346
+ if (resolved?.kind === 'node')
347
+ pending.push(resolved);
348
+ }
349
+ }
350
+ return keys;
351
+ }
352
+ function targetContract(term, use) {
353
+ if (use.kind === 'object')
354
+ return term === 'object' ? use.object : undefined;
355
+ if (term === 'source')
356
+ return use.source;
357
+ if (term === 'target')
358
+ return use.target;
359
+ return undefined;
360
+ }
361
+ function edgeAlternatives(edges, typing) {
362
+ let result = [[]];
363
+ for (const edge of edges) {
364
+ const variants = variantsForEdge(edge, typing);
365
+ if (variants.length === 0)
366
+ return [];
367
+ const next = [];
368
+ for (const prefix of result) {
369
+ for (const variant of variants)
370
+ next.push([...prefix, variant]);
371
+ }
372
+ result = next;
373
+ }
374
+ return result;
375
+ }
376
+ function variantsForEdge(use, typing) {
377
+ const edge = use.pattern;
378
+ const declaration = typing.scope.edgeDeclaration(edge.class);
379
+ if (declaration === undefined)
380
+ return [];
381
+ const endpoints = endpointPair(declaration);
382
+ const bounds = edge.repeat ?? { min: 1, max: 1 };
383
+ if (!Number.isInteger(bounds.min) ||
384
+ !Number.isInteger(bounds.max) ||
385
+ bounds.min < 0 ||
386
+ bounds.max < bounds.min ||
387
+ bounds.max > limits.policy.repetition) {
388
+ return [];
389
+ }
390
+ const sourceKey = termKey(edge.source, use.namespace);
391
+ const targetKey = termKey(edge.target, use.namespace);
392
+ const variants = [];
393
+ for (let length = bounds.min; length <= bounds.max; length++) {
394
+ if (length === 0) {
395
+ variants.push({ constraints: [], equalities: [[sourceKey, targetKey]] });
396
+ continue;
397
+ }
398
+ const orientationCount = declaration.orientation === 'undirected' ? 2 ** length : 1;
399
+ for (let mask = 0; mask < orientationCount; mask++) {
400
+ const orientations = Array.from({ length }, (_, index) => declaration.orientation === 'undirected' && (mask & (1 << index)) !== 0);
401
+ let transitionsValid = true;
402
+ for (let index = 0; index + 1 < length; index++) {
403
+ const incoming = endEndpoint(endpoints, orientations[index] ?? false);
404
+ const outgoing = startEndpoint(endpoints, orientations[index + 1] ?? false);
405
+ if (!typing.endpointsOverlap(incoming.accepts, outgoing.accepts)) {
406
+ transitionsValid = false;
407
+ break;
408
+ }
409
+ }
410
+ if (!transitionsValid)
411
+ continue;
412
+ const first = startEndpoint(endpoints, orientations[0] ?? false);
413
+ const last = endEndpoint(endpoints, orientations[length - 1] ?? false);
414
+ variants.push({
415
+ constraints: [
416
+ [sourceKey, first.accepts],
417
+ [targetKey, last.accepts],
418
+ ],
419
+ equalities: [],
420
+ });
421
+ }
422
+ }
423
+ return uniqueBy(variants, edgeVariantKey);
424
+ }
425
+ /** The two endpoints of an Edge Class, a directed one's as source then target. */
426
+ function endpointPair(declaration) {
427
+ return declaration.orientation === 'directed'
428
+ ? [declaration.endpoints.source, declaration.endpoints.target]
429
+ : declaration.endpoints;
430
+ }
431
+ function startEndpoint(endpoints, reversed) {
432
+ return reversed ? endpoints[1] : endpoints[0];
433
+ }
434
+ function endEndpoint(endpoints, reversed) {
435
+ return reversed ? endpoints[0] : endpoints[1];
436
+ }
437
+ /** The values with distinct keys, each at its key's first position and holding its last value. */
438
+ function uniqueBy(values, key) {
439
+ return [...new Map(values.map((value) => [key(value), value])).values()];
440
+ }
441
+ function edgeVariantKey(variant) {
442
+ const constraints = variant.constraints.map(([term, accepts]) => `${term}:${classSetKey(accepts)}`);
443
+ const equalities = variant.equalities.map(([left, right]) => `${left}:${right}`);
444
+ return `${constraints.join('|')}=${equalities.join('|')}`;
445
+ }
446
+ function candidateKey(candidate) {
447
+ if (candidate.kind === 'exact')
448
+ return `exact:${definitionRefIndex(candidate.ref)}`;
449
+ if (candidate.kind === 'open')
450
+ return `open:${classSetKey(candidate.requirements)}`;
451
+ return `node:${candidate.lists.map(classSetKey).sort().join('|')}`;
452
+ }
453
+ function classSetKey(refs) {
454
+ return refs.map(definitionRefIndex).sort().join(',');
455
+ }
@@ -65,20 +65,20 @@ export interface PolicyEdgePattern {
65
65
  }
66
66
  export type PolicyPatternExpression = PolicyEdgePattern | PolicySameNode<PolicyPatternTerm> | {
67
67
  readonly exists: {
68
- readonly nodes: readonly PolicyVariable[];
68
+ readonly nodes: readonly [PolicyVariable, ...PolicyVariable[]];
69
69
  readonly where: PolicyPatternExpression;
70
70
  };
71
71
  } | {
72
- readonly allOf: readonly PolicyPatternExpression[];
72
+ readonly allOf: readonly [PolicyPatternExpression, ...PolicyPatternExpression[]];
73
73
  } | {
74
- readonly anyOf: readonly PolicyPatternExpression[];
74
+ readonly anyOf: readonly [PolicyPatternExpression, ...PolicyPatternExpression[]];
75
75
  };
76
76
  export type PolicyExpression = {
77
77
  readonly match: PolicyPatternExpression;
78
78
  } | {
79
- readonly allOf: readonly PolicyRef[];
79
+ readonly allOf: readonly [PolicyRef, ...PolicyRef[]];
80
80
  } | {
81
- readonly anyOf: readonly PolicyRef[];
81
+ readonly anyOf: readonly [PolicyRef, ...PolicyRef[]];
82
82
  };
83
83
  export interface PolicyDefinition extends DefinitionBase<PolicyRef> {
84
84
  readonly expression: PolicyExpression;
@@ -90,23 +90,63 @@ export type PolicyObjectRef = ClassRef | FunctionRef | PolicyRef | ViewRef | Cor
90
90
  export declare function policyObjectKey(ref: PolicyObjectRef): string;
91
91
  export declare function policyObjectOrigin(ref: PolicyObjectRef): string;
92
92
  export declare function projectedMemberClass(ref: Exclude<PolicyObjectRef, CoreRef>): ClassRef;
93
+ export type ClassObservation = 'read' | 'traverse';
94
+ export type ClassWrite = 'create' | 'update' | 'delete';
95
+ export type ClassOperation = ClassObservation | ClassWrite;
96
+ /**
97
+ * Every Class slot: the observations, which admit every caller when absent, then the writes, which
98
+ * admit only the Domain that declares the Class when absent.
99
+ */
100
+ export declare const CLASS_OPERATIONS: readonly ClassOperation[];
101
+ export declare function isClassObservation(operation: ClassOperation): operation is ClassObservation;
93
102
  /**
94
103
  * One Class observation slot: a named Policy, or `false`, the rule no caller satisfies. Its other
95
104
  * value has no spelling there: an absent observation Policy already means `true`.
96
105
  */
97
106
  export type ClassPolicy = PolicyRef | false;
98
- /** What a Node Class rule may check: the observed Node, or one exact projected member. */
107
+ /**
108
+ * One Class write slot: a named Policy, or `true`, the rule every Identity satisfies. Its other
109
+ * value has no spelling there: an absent write Policy already means the owning Domain only.
110
+ */
111
+ export type ClassWritePolicy = PolicyRef | true;
112
+ /** What a Class rule may check: the observed or written instance, or one exact projected member. */
99
113
  export type ClassRuleObject = Extract<PolicyCheckObject, {
100
114
  readonly kind: 'self' | 'ref';
101
115
  }>;
102
116
  /**
103
- * Policy checks deciding one Node Class observation. `self` is the observed Node; a `ref` object
104
- * is the same Node for every candidate. A lone check of `self` is spelled as its Policy reference.
117
+ * Policy checks deciding one Node Class slot. `self` is the observed or written Node; a `ref`
118
+ * object is the same Node for every candidate. A lone check of `self` is spelled as its Policy
119
+ * reference.
105
120
  */
106
121
  export type ClassRuleChecks = PolicyCheckExpression<PolicyRef, ClassRuleObject>;
122
+ /**
123
+ * Policy checks deciding one Edge Class slot. `self` is the observed or written Edge, checked by a
124
+ * Policy whose source and target are its endpoints; a `ref` object is one exact member, the same
125
+ * Node for every candidate. A lone check of `self` is spelled as its Policy reference.
126
+ */
127
+ export type EdgeRuleChecks = ClassRuleChecks;
128
+ /** What a Node create rule may check: one exact projected member, since the Node is not yet. */
129
+ export type CreateRuleObject = Extract<PolicyCheckObject, {
130
+ readonly kind: 'ref';
131
+ }>;
132
+ /** Policy checks deciding the creation of a Node: every object is a `ref` member. */
133
+ export type CreateRuleChecks = PolicyCheckExpression<PolicyRef, CreateRuleObject>;
107
134
  /** One Node Class observation slot: a Class Policy, or Policy checks over the observed Node. */
108
135
  export type NodeClassPolicy = ClassPolicy | ClassRuleChecks;
109
- export declare function isClassRuleChecks(value: ClassPolicy | ClassRuleChecks | undefined): value is ClassRuleChecks;
136
+ /** One Node Class update or delete slot: a write Policy, or Policy checks over the written Node. */
137
+ export type NodeClassWritePolicy = ClassWritePolicy | ClassRuleChecks;
138
+ /**
139
+ * The Node Class create slot: `true`, or Policy checks over members. A named Policy alone has no
140
+ * object there, so it has no spelling.
141
+ */
142
+ export type NodeClassCreatePolicy = true | CreateRuleChecks;
143
+ /** One Edge Class observation slot: a Class Policy, or Policy checks over the observed Edge. */
144
+ export type EdgeClassPolicy = ClassPolicy | EdgeRuleChecks;
145
+ /** One Edge Class write slot: a write Policy, or Policy checks over the written Edge. */
146
+ export type EdgeClassWritePolicy = ClassWritePolicy | EdgeRuleChecks;
147
+ /** The value of any Class slot. */
148
+ export type ClassSlotPolicy = PolicyRef | boolean | ClassRuleChecks;
149
+ export declare function isClassRuleChecks(value: ClassSlotPolicy | undefined): value is ClassRuleChecks;
110
150
  /**
111
151
  * Whether every way Policy checks can hold passes through a check, so that the caller decides each
112
152
  * admission. `sameNode` compares two objects and names no caller.
@@ -33,6 +33,20 @@ export function projectedMemberClass(ref) {
33
33
  function kernelClassRef(name) {
34
34
  return Object.freeze({ origin: 'kernel.astrale.ai', kind: 'class', name });
35
35
  }
36
+ /**
37
+ * Every Class slot: the observations, which admit every caller when absent, then the writes, which
38
+ * admit only the Domain that declares the Class when absent.
39
+ */
40
+ export const CLASS_OPERATIONS = Object.freeze([
41
+ 'read',
42
+ 'traverse',
43
+ 'create',
44
+ 'update',
45
+ 'delete',
46
+ ]);
47
+ export function isClassObservation(operation) {
48
+ return operation === 'read' || operation === 'traverse';
49
+ }
36
50
  export function isClassRuleChecks(value) {
37
51
  return (typeof value === 'object' &&
38
52
  ('check' in value || 'sameNode' in value || 'allOf' in value || 'anyOf' in value));
@@ -1,4 +1,4 @@
1
- import type { NodeClassPolicy, PolicyCheckExpression, PolicyExpression, PolicyPatternExpression } from '../model/policy.js';
1
+ import type { ClassSlotPolicy, PolicyCheckExpression, PolicyExpression, PolicyPatternExpression } from '../model/policy.js';
2
2
  export declare function normalizePolicyExpression(value: PolicyExpression): PolicyExpression;
3
3
  /**
4
4
  * The fixed point of the single pass: a Pattern the single pass reproduces is returned unchanged,
@@ -6,10 +6,10 @@ export declare function normalizePolicyExpression(value: PolicyExpression): Poli
6
6
  */
7
7
  export declare function normalizePolicyPattern(value: PolicyPatternExpression): PolicyPatternExpression;
8
8
  /**
9
- * The one spelling of a Node Class observation rule: normalized Policy checks without a composition
10
- * of one operand, or the Policy that a lone check of `self` names, which is how a Class has always
11
- * declared one. Callable checks keep their compositions of one operand: their revisions predate
12
- * this rule.
9
+ * The one spelling of a Class rule: normalized Policy checks without a composition of one operand,
10
+ * or the Policy that a lone check of `self` names, which is how a Class has always declared one.
11
+ * Callable checks keep their compositions of one operand: their revisions predate this rule. A
12
+ * create rule checks no `self`, so it keeps its checks.
13
13
  */
14
- export declare function normalizeClassRule(value: NodeClassPolicy): NodeClassPolicy;
14
+ export declare function normalizeClassRule<Slot extends ClassSlotPolicy>(value: Slot): Slot;
15
15
  export declare function normalizePolicyChecks(value: PolicyCheckExpression): PolicyCheckExpression;