@astrale-os/kernel-dsl 0.2.0-beta.46 → 0.2.0-beta.48

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 (159) hide show
  1. package/dist/v1/addressing/patterns.d.ts +0 -5
  2. package/dist/v1/addressing/patterns.js +5 -5
  3. package/dist/v1/builder/callable/authoring.d.ts +1 -1
  4. package/dist/v1/builder/class/authoring.d.ts +0 -12
  5. package/dist/v1/builder/class/property.d.ts +4 -2
  6. package/dist/v1/builder/class/property.js +9 -1
  7. package/dist/v1/builder/index.d.ts +1 -1
  8. package/dist/v1/builder/lowering/callable.d.ts +2 -1
  9. package/dist/v1/builder/lowering/core.d.ts +3 -2
  10. package/dist/v1/builder/lowering/schema/compile.js +15 -2
  11. package/dist/v1/builder/lowering/value/compile.js +3 -0
  12. package/dist/v1/builder/lowering/value/zod.d.ts +3 -2
  13. package/dist/v1/builder/lowering/view.d.ts +4 -3
  14. package/dist/v1/builder/lowering/view.js +2 -14
  15. package/dist/v1/builder/schema/define.d.ts +4 -2
  16. package/dist/v1/builder/schema/diagnostic.d.ts +1 -1
  17. package/dist/v1/builder/schema/handle.d.ts +2 -1
  18. package/dist/v1/builder/schema/input.d.ts +8 -0
  19. package/dist/v1/builder/schema/projection/callable.d.ts +51 -0
  20. package/dist/v1/builder/schema/projection/callable.js +1 -0
  21. package/dist/v1/builder/schema/projection/class.d.ts +89 -0
  22. package/dist/v1/builder/schema/projection/class.js +1 -0
  23. package/dist/v1/builder/schema/projection/core-input.d.ts +32 -0
  24. package/dist/v1/builder/schema/projection/core-input.js +1 -0
  25. package/dist/v1/builder/schema/projection/domain.d.ts +59 -0
  26. package/dist/v1/builder/schema/projection/domain.js +1 -0
  27. package/dist/v1/builder/schema/projection/identity.d.ts +39 -0
  28. package/dist/v1/builder/schema/projection/identity.js +1 -0
  29. package/dist/v1/builder/schema/projection/model.d.ts +59 -0
  30. package/dist/v1/builder/schema/projection/model.js +1 -0
  31. package/dist/v1/builder/schema/projection/property.d.ts +32 -0
  32. package/dist/v1/builder/schema/projection/property.js +1 -0
  33. package/dist/v1/builder/schema/projection/resolved-class.d.ts +76 -0
  34. package/dist/v1/builder/schema/projection/resolved-class.js +1 -0
  35. package/dist/v1/builder/schema/projection.d.ts +4 -375
  36. package/dist/v1/builder/view/authoring.d.ts +3 -7
  37. package/dist/v1/builder/view/authoring.js +5 -2
  38. package/dist/v1/bundle/structure.d.ts +2 -1
  39. package/dist/v1/compiled/admission/accept.d.ts +1 -1
  40. package/dist/v1/compiled/admission/accept.js +7 -1001
  41. package/dist/v1/compiled/admission/closure.d.ts +3 -0
  42. package/dist/v1/compiled/admission/closure.js +173 -0
  43. package/dist/v1/compiled/admission/diagnostic.d.ts +7 -0
  44. package/dist/v1/compiled/admission/diagnostic.js +13 -0
  45. package/dist/v1/compiled/admission/revision.js +2 -0
  46. package/dist/v1/compiled/admission/semantics/cardinality.d.ts +5 -0
  47. package/dist/v1/compiled/admission/semantics/cardinality.js +113 -0
  48. package/dist/v1/compiled/admission/semantics/class.d.ts +5 -0
  49. package/dist/v1/compiled/admission/semantics/class.js +125 -0
  50. package/dist/v1/compiled/admission/semantics/context.d.ts +60 -0
  51. package/dist/v1/compiled/admission/semantics/context.js +81 -0
  52. package/dist/v1/compiled/admission/semantics/core.d.ts +35 -0
  53. package/dist/v1/compiled/admission/semantics/core.js +123 -0
  54. package/dist/v1/compiled/admission/semantics/edge.d.ts +8 -0
  55. package/dist/v1/compiled/admission/semantics/edge.js +89 -0
  56. package/dist/v1/compiled/admission/semantics/policy/admit.d.ts +4 -0
  57. package/dist/v1/compiled/admission/semantics/policy/admit.js +57 -0
  58. package/dist/v1/compiled/admission/semantics/policy/callable.d.ts +5 -0
  59. package/dist/v1/compiled/admission/semantics/policy/callable.js +72 -0
  60. package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +24 -0
  61. package/dist/v1/compiled/admission/semantics/policy/contracts.js +45 -0
  62. package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +8 -0
  63. package/dist/v1/compiled/admission/semantics/policy/equality.js +27 -0
  64. package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +9 -0
  65. package/dist/v1/compiled/admission/semantics/policy/measure.js +81 -0
  66. package/dist/v1/compiled/admission/semantics/policy/parity.d.ts +4 -0
  67. package/dist/v1/compiled/admission/semantics/policy/parity.js +126 -0
  68. package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +8 -0
  69. package/dist/v1/compiled/admission/semantics/policy/pattern.js +78 -0
  70. package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +28 -0
  71. package/dist/v1/compiled/admission/semantics/policy/typing.js +206 -0
  72. package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +10 -0
  73. package/dist/v1/compiled/admission/semantics/policy/variants.js +65 -0
  74. package/dist/v1/compiled/admission/semantics.d.ts +1 -1
  75. package/dist/v1/compiled/admission/semantics.js +8 -1214
  76. package/dist/v1/compiled/admission/wire/callable.d.ts +6 -0
  77. package/dist/v1/compiled/admission/wire/callable.js +90 -0
  78. package/dist/v1/compiled/admission/wire/class.d.ts +4 -0
  79. package/dist/v1/compiled/admission/wire/class.js +117 -0
  80. package/dist/v1/compiled/admission/wire/core.d.ts +5 -0
  81. package/dist/v1/compiled/admission/wire/core.js +32 -0
  82. package/dist/v1/compiled/admission/wire/dependency.d.ts +14 -0
  83. package/dist/v1/compiled/admission/wire/dependency.js +43 -0
  84. package/dist/v1/compiled/admission/wire/entry.d.ts +5 -0
  85. package/dist/v1/compiled/admission/wire/entry.js +100 -0
  86. package/dist/v1/compiled/admission/wire/pattern.d.ts +12 -0
  87. package/dist/v1/compiled/admission/wire/pattern.js +111 -0
  88. package/dist/v1/compiled/admission/wire/policy.d.ts +5 -0
  89. package/dist/v1/compiled/admission/wire/policy.js +168 -0
  90. package/dist/v1/compiled/admission/wire/program.d.ts +4 -0
  91. package/dist/v1/compiled/admission/wire/program.js +52 -0
  92. package/dist/v1/compiled/admission/wire/property.d.ts +4 -0
  93. package/dist/v1/compiled/admission/wire/property.js +74 -0
  94. package/dist/v1/compiled/admission/wire/reference.d.ts +8 -0
  95. package/dist/v1/compiled/admission/wire/reference.js +33 -0
  96. package/dist/v1/compiled/admission/wire/value.d.ts +29 -0
  97. package/dist/v1/compiled/admission/wire/value.js +98 -0
  98. package/dist/v1/compiled/admission/wire/view.d.ts +3 -0
  99. package/dist/v1/compiled/admission/wire/view.js +17 -0
  100. package/dist/v1/compiled/compiler/compile.js +3 -0
  101. package/dist/v1/compiled/model/schema.d.ts +5 -1
  102. package/dist/v1/domain/create.js +0 -19
  103. package/dist/v1/domain/model/domain.d.ts +0 -1
  104. package/dist/v1/domain/projection/classes.js +2 -9
  105. package/dist/v1/index.d.ts +1 -1
  106. package/dist/v1/language/class/inheritance.d.ts +12 -0
  107. package/dist/v1/language/class/inheritance.js +25 -0
  108. package/dist/v1/language/class/model/property.d.ts +3 -0
  109. package/dist/v1/language/class/resolved.d.ts +5 -1
  110. package/dist/v1/language/definition/metadata.d.ts +8 -0
  111. package/dist/v1/language/definition/metadata.js +12 -0
  112. package/dist/v1/language/value/model/blob.d.ts +0 -2
  113. package/dist/v1/language/value/model/blob.js +2 -2
  114. package/dist/v1/language/value/model/instant.d.ts +0 -2
  115. package/dist/v1/language/value/model/instant.js +1 -1
  116. package/dist/v1/language/value/model/schema.d.ts +2 -1
  117. package/dist/v1/language/value/model/schema.js +1 -5
  118. package/dist/v1/language/value/reference/registry.d.ts +2 -1
  119. package/dist/v1/language/value/regexp/syntax.d.ts +2 -1
  120. package/dist/v1/language/view/model/view.d.ts +2 -4
  121. package/dist/v1/language/view/resolved.d.ts +2 -2
  122. package/dist/v1/schema/analysis/class.d.ts +4 -2
  123. package/dist/v1/schema/analysis/class.js +1 -0
  124. package/dist/v1/schema/canonical/revision.d.ts +2 -1
  125. package/dist/v1/schema/compatibility/comparators/classes.d.ts +2 -1
  126. package/dist/v1/schema/compatibility/context.d.ts +6 -2
  127. package/dist/v1/schema/compatibility/context.js +12 -6
  128. package/dist/v1/schema/compatibility/coordinate.d.ts +2 -1
  129. package/dist/v1/schema/compatibility/fields.d.ts +2 -0
  130. package/dist/v1/schema/compatibility/fields.js +1 -0
  131. package/dist/v1/schema/compatibility/references.js +1 -10
  132. package/dist/v1/schema/compatibility/report.d.ts +2 -1
  133. package/dist/v1/schema/compatibility/scope.d.ts +0 -4
  134. package/dist/v1/schema/compatibility/scope.js +1 -1
  135. package/dist/v1/schema/diagnostic.d.ts +1 -1
  136. package/dist/v1/schema/model/schema.d.ts +5 -1
  137. package/dist/v1/schema/normalization/domain.js +12 -6
  138. package/dist/v1/schema/resolution/definition.index.d.ts +1 -2
  139. package/dist/v1/schema/resolution/definition.index.js +0 -3
  140. package/dist/v1/schema/resolution/domain.d.ts +4 -1
  141. package/dist/v1/schema/resolution/domain.js +6 -7
  142. package/dist/v1/schema/resolution/origins.d.ts +1 -1
  143. package/dist/v1/schema/resolution/origins.js +0 -5
  144. package/dist/v1/schema/validation/class.js +19 -50
  145. package/dist/v1/schema/validation/core.js +1 -27
  146. package/dist/v1/schema/validation/domain.d.ts +2 -1
  147. package/dist/v1/schema/validation/domain.structure.d.ts +0 -2
  148. package/dist/v1/schema/validation/domain.structure.js +9 -8
  149. package/dist/v1/schema/validation/policy/context.js +5 -16
  150. package/dist/v1/schema/validation/view.js +14 -9
  151. package/dist/value/accept.d.ts +1 -1
  152. package/dist/value/accept.js +32 -6
  153. package/dist/value/canonical.js +10 -2
  154. package/dist/value/immutable.optimization.d.ts +4 -1
  155. package/dist/value/immutable.optimization.js +8 -2
  156. package/dist/value/limits.d.ts +1 -1
  157. package/dist/value/unicode.d.ts +3 -0
  158. package/dist/value/unicode.js +27 -0
  159. package/package.json +1 -1
@@ -0,0 +1,123 @@
1
+ import { Key } from '../../../addressing/index.js';
2
+ import { isMethodExecutable } from '../../../language/callable/executable.js';
3
+ import {} from '../../../language/core/model/core.js';
4
+ import { policyObjectOrigin, policyObjectKey, projectedMemberClass, } from '../../../language/index.js';
5
+ import { bindValueProgram } from '../../../language/value/compile/load.js';
6
+ import { validateValueProgram } from '../../../language/value/evaluate/program.js';
7
+ import {} from '../../model/schema.js';
8
+ import { fail } from '../diagnostic.js';
9
+ import { validateCoreEdgeSet } from './cardinality.js';
10
+ import { isCompiledEdge, classSatisfiesAny, } from './context.js';
11
+ /** Admit local Core Nodes, Properties and Edge endpoint contracts. */
12
+ export function validateCore(candidate, context) {
13
+ for (const [entryIndex, entry] of candidate.closure.entries()) {
14
+ const nodes = new Map();
15
+ for (const [index, value] of entry.definitions.core.entries()) {
16
+ const path = `/closure/${entryIndex}/definitions/core/${index}`;
17
+ const classValue = context.classes.get(Key.of(value.class));
18
+ if (value.class.origin !== entry.origin ||
19
+ classValue?.value.kind !== 'node' ||
20
+ classValue.value.abstract)
21
+ fail(`${path}/class`, 'A Core Node requires a local concrete Node Class.');
22
+ const analysis = context.analyses.get(Key.of(value.class));
23
+ if (analysis === undefined)
24
+ fail(`${path}/class`, 'Core Node Class analysis is absent.');
25
+ validateCoreProperties(value.properties, analysis, `${path}/properties`);
26
+ nodes.set(Key.of(value.ref), {
27
+ key: Key.of(value.ref),
28
+ value,
29
+ class: classValue,
30
+ analysis,
31
+ pointer: path,
32
+ });
33
+ }
34
+ const edges = [];
35
+ for (const [index, value] of entry.facts.core.entries()) {
36
+ const path = `/closure/${entryIndex}/facts/core/${index}`;
37
+ const classValue = context.classes.get(Key.of(value.class));
38
+ if (value.class.origin !== entry.origin ||
39
+ classValue === undefined ||
40
+ !isCompiledEdge(classValue.value) ||
41
+ classValue.value.abstract)
42
+ fail(`${path}/class`, 'A Core Edge requires a local concrete Edge Class.');
43
+ const analysis = context.analyses.get(Key.of(value.class));
44
+ if (analysis === undefined)
45
+ fail(`${path}/class`, 'Core Edge Class analysis is absent.');
46
+ validateCoreProperties(value.properties, analysis, `${path}/properties`);
47
+ const source = resolveCoreEndpoint(context, entry, value.source, nodes, `${path}/source`);
48
+ const target = resolveCoreEndpoint(context, entry, value.target, nodes, `${path}/target`);
49
+ const declaration = classValue.value;
50
+ const satisfies = declaration.orientation === 'directed'
51
+ ? endpointSatisfies(context, source, declaration.endpoints.source.accepts) &&
52
+ endpointSatisfies(context, target, declaration.endpoints.target.accepts)
53
+ : (endpointSatisfies(context, source, declaration.endpoints[0].accepts) &&
54
+ endpointSatisfies(context, target, declaration.endpoints[1].accepts)) ||
55
+ (endpointSatisfies(context, source, declaration.endpoints[1].accepts) &&
56
+ endpointSatisfies(context, target, declaration.endpoints[0].accepts));
57
+ if (!satisfies)
58
+ fail(path, 'Core Edge endpoints do not satisfy its exact Class.');
59
+ edges.push({
60
+ source,
61
+ target,
62
+ value,
63
+ class: classValue,
64
+ pointer: path,
65
+ });
66
+ }
67
+ validateCoreEdgeSet(context, entry, entryIndex, nodes, edges);
68
+ }
69
+ }
70
+ function validateCoreProperties(values, analysis, path) {
71
+ for (const key of Object.keys(values))
72
+ if (!analysis.properties.has(key))
73
+ fail(`${path}/${escapePointer(key)}`, 'Core properties contain an unknown Property key.');
74
+ for (const property of analysis.properties.values()) {
75
+ if (!Object.hasOwn(values, property.key)) {
76
+ if (property.declaration.required && property.declaration.auto === undefined)
77
+ fail(`${path}/${escapePointer(property.key)}`, 'Core properties omit a required Property.');
78
+ continue;
79
+ }
80
+ if (property.declaration.auto !== undefined)
81
+ fail(`${path}/${escapePointer(property.key)}`, 'Core properties cannot author an automatic Property.');
82
+ if (validateValueProgram(bindValueProgram(property.entry.values[property.declaration.value], property.entry.patterns), values[property.key]).length > 0)
83
+ fail(`${path}/${escapePointer(property.key)}`, 'Core Property value does not satisfy its exact contract.');
84
+ }
85
+ }
86
+ function resolveCoreEndpoint(context, entry, ref, nodes, path) {
87
+ if (ref.kind === 'domain')
88
+ return { key: 'domain' };
89
+ const undeclared = () => fail(path, 'Core endpoint does not name a declared local Definition.');
90
+ if (policyObjectOrigin(ref) !== entry.origin)
91
+ return undeclared();
92
+ if (ref.kind === 'core')
93
+ return nodes.get(Key.of(ref)) ?? undeclared();
94
+ if (!declaresProjectedMember(context, entry, ref))
95
+ return undeclared();
96
+ return { key: policyObjectKey(ref), class: projectedMemberClass(ref), pointer: path };
97
+ }
98
+ /** Only a projected declaration can carry a Core fact; an abstract Method is never projected. */
99
+ function declaresProjectedMember(context, entry, ref) {
100
+ if (ref.kind === 'method') {
101
+ const owner = context.classes.get(Key.of(ref.owner))?.value;
102
+ const method = owner?.kind === 'node' ? owner.methods.find((value) => value.name === ref.name) : undefined;
103
+ return method !== undefined && isMethodExecutable(owner, method);
104
+ }
105
+ const declarations = ref.kind === 'class'
106
+ ? entry.definitions.classes
107
+ : ref.kind === 'function'
108
+ ? entry.definitions.functions
109
+ : ref.kind === 'policy'
110
+ ? entry.definitions.policies
111
+ : entry.definitions.views;
112
+ return declarations.some((declaration) => declaration.ref.name === ref.name);
113
+ }
114
+ function endpointSatisfies(context, endpoint, accepts) {
115
+ if ('value' in endpoint)
116
+ return classSatisfiesAny(context, endpoint.value.class, accepts);
117
+ if ('class' in endpoint)
118
+ return classSatisfiesAny(context, endpoint.class, accepts);
119
+ return true;
120
+ }
121
+ function escapePointer(value) {
122
+ return value.replaceAll('~', '~0').replaceAll('/', '~1');
123
+ }
@@ -0,0 +1,8 @@
1
+ import { type EdgeCount, type IncidentEndpoint } from '../../../language/class/model/edge.js';
2
+ import { type SemanticIndex } from './context.js';
3
+ /** Check Edge endpoint contracts and safe inheritance refinement. */
4
+ export declare function validateEdges(context: SemanticIndex): void;
5
+ /** Compare undirected endpoint acceptance and cardinality contracts. */
6
+ export declare function sameIncidentEndpoint(left: IncidentEndpoint, right: IncidentEndpoint): boolean;
7
+ /** Interpret an Edge count as inclusive degree bounds. */
8
+ export declare function countBounds(value: EdgeCount): readonly [number, number];
@@ -0,0 +1,89 @@
1
+ import { Key } from '../../../addressing/index.js';
2
+ import { compareUnicode } from '../../../addressing/ordering.js';
3
+ import { isGraphRoot } from '../../../language/class/inheritance.js';
4
+ import {} from '../../../language/class/model/edge.js';
5
+ import { fail } from '../diagnostic.js';
6
+ import { isCompiledEdge, classSatisfiesAny, } from './context.js';
7
+ /** Check Edge endpoint contracts and safe inheritance refinement. */
8
+ export function validateEdges(context) {
9
+ for (const located of context.classes.values()) {
10
+ if (!isCompiledEdge(located.value))
11
+ continue;
12
+ const edge = located.value;
13
+ const endpoints = edge.orientation === 'directed'
14
+ ? [edge.endpoints.source, edge.endpoints.target]
15
+ : edge.endpoints;
16
+ if (endpoints[0].role === endpoints[1].role)
17
+ fail(`${located.pointer}/endpoints`, 'Edge endpoint roles must differ.');
18
+ for (const [endpointIndex, endpoint] of endpoints.entries()) {
19
+ const seen = new Set();
20
+ for (const [acceptIndex, ref] of endpoint.accepts.entries()) {
21
+ const key = Key.of(ref);
22
+ if (seen.has(key))
23
+ fail(`${located.pointer}/endpoints/${endpointIndex}/accepts/${acceptIndex}`, 'Edge endpoint repeats an accepted Class.');
24
+ seen.add(key);
25
+ if (context.classes.get(key)?.value.kind !== 'node')
26
+ fail(`${located.pointer}/endpoints/${endpointIndex}/accepts/${acceptIndex}`, 'Edge endpoint must accept a Node Class.');
27
+ }
28
+ }
29
+ for (const [parentIndex, parentRef] of edge.extends.entries()) {
30
+ const parent = context.classes.get(Key.of(parentRef))?.value;
31
+ if (parent !== undefined && isCompiledEdge(parent) && !edgeRefines(context, edge, parent)) {
32
+ fail(`${located.pointer}/extends/${parentIndex}`, 'Edge Class does not safely refine its parent.');
33
+ }
34
+ }
35
+ }
36
+ }
37
+ function edgeRefines(context, child, parent) {
38
+ if (isGraphRoot(parent))
39
+ return true;
40
+ if (child.orientation !== parent.orientation)
41
+ return false;
42
+ if (parent.constraints.noSelf === true && child.constraints.noSelf !== true)
43
+ return false;
44
+ if (parent.constraints.acyclic === true && child.constraints.acyclic !== true)
45
+ return false;
46
+ if (child.orientation === 'directed' && parent.orientation === 'directed') {
47
+ return (endpointRefines(context, child.endpoints.source, parent.endpoints.source) &&
48
+ countRefines(child.endpoints.source.outgoing, parent.endpoints.source.outgoing) &&
49
+ endpointRefines(context, child.endpoints.target, parent.endpoints.target) &&
50
+ countRefines(child.endpoints.target.incoming, parent.endpoints.target.incoming));
51
+ }
52
+ if (child.orientation !== 'undirected' || parent.orientation !== 'undirected')
53
+ return false;
54
+ const refine = (a, b) => endpointRefines(context, child.endpoints[a], parent.endpoints[b]) &&
55
+ countRefines(child.endpoints[a].incident, parent.endpoints[b].incident);
56
+ const direct = refine(0, 0) && refine(1, 1);
57
+ if (direct)
58
+ return true;
59
+ return refine(0, 1) && refine(1, 0);
60
+ }
61
+ function endpointRefines(context, child, parent) {
62
+ return child.accepts.every((accepted) => classSatisfiesAny(context, accepted, parent.accepts));
63
+ }
64
+ function countRefines(child, parent) {
65
+ const [childMin, childMax] = countBounds(child);
66
+ const [parentMin, parentMax] = countBounds(parent);
67
+ return childMin >= parentMin && childMax <= parentMax;
68
+ }
69
+ /** Compare undirected endpoint acceptance and cardinality contracts. */
70
+ export function sameIncidentEndpoint(left, right) {
71
+ const a = left.accepts.map(Key.of).sort(compareUnicode);
72
+ const b = right.accepts.map(Key.of).sort(compareUnicode);
73
+ return (left.incident === right.incident &&
74
+ a.length === b.length &&
75
+ a.every((value, index) => value === b[index]));
76
+ }
77
+ /** Interpret an Edge count as inclusive degree bounds. */
78
+ export function countBounds(value) {
79
+ switch (value) {
80
+ case '0..*':
81
+ return [0, Number.POSITIVE_INFINITY];
82
+ case '1..*':
83
+ return [1, Number.POSITIVE_INFINITY];
84
+ case '0..1':
85
+ return [0, 1];
86
+ case '1':
87
+ return [1, 1];
88
+ }
89
+ }
@@ -0,0 +1,4 @@
1
+ import { type CompiledSchema } from '../../../model/schema.js';
2
+ import { type SemanticIndex } from '../context.js';
3
+ /** Admit each entry’s Policy graph and all of its Policy uses. */
4
+ export declare function validatePolicies(candidate: CompiledSchema, context: SemanticIndex, admitted: ReadonlyMap<string, ReadonlySet<string>>): void;
@@ -0,0 +1,57 @@
1
+ import { Key } from '../../../../addressing/index.js';
2
+ import {} from '../../../model/schema.js';
3
+ import { fail } from '../../diagnostic.js';
4
+ import {} from '../context.js';
5
+ import { validateCallablePolicy } from './callable.js';
6
+ import { validatePolicyParity } from './parity.js';
7
+ import { validatePolicyExpression } from './pattern.js';
8
+ /** Admit each entry’s Policy graph and all of its Policy uses. */
9
+ export function validatePolicies(candidate, context, admitted) {
10
+ for (const [entryIndex, entry] of candidate.closure.entries()) {
11
+ const localPolicies = new Map(entry.definitions.policies.map((value) => [value.ref.name, value]));
12
+ for (const [policyIndex, policy] of entry.definitions.policies.entries()) {
13
+ validatePolicyExpression(context, entry, policy.expression, `/closure/${entryIndex}/definitions/policies/${policyIndex}/expression`, localPolicies);
14
+ }
15
+ validatePolicyCycles(entry, localPolicies, entryIndex);
16
+ validatePolicyParity(context, entry, entryIndex, localPolicies, admitted.get(entry.origin));
17
+ for (const [functionIndex, callable] of entry.definitions.functions.entries()) {
18
+ if (callable.policy !== undefined)
19
+ validateCallablePolicy(context, entry, callable.policy, typeof callable.input === 'number' ? callable.input : callable.input.metadata, callable.fields, false, `/closure/${entryIndex}/definitions/functions/${functionIndex}/policy`);
20
+ }
21
+ for (const [classIndex, definition] of entry.definitions.classes.entries()) {
22
+ for (const [kind, ref] of Object.entries(definition.policies)) {
23
+ if (ref !== undefined &&
24
+ (ref.origin !== entry.origin || context.policies.get(Key.of(ref)) === undefined)) {
25
+ fail(`/closure/${entryIndex}/definitions/classes/${classIndex}/policies/${kind}`, 'Class Policies must name a local Policy Definition.');
26
+ }
27
+ }
28
+ if (definition.kind !== 'node')
29
+ continue;
30
+ for (const [methodIndex, callable] of definition.methods.entries()) {
31
+ if (callable.policy !== undefined)
32
+ validateCallablePolicy(context, entry, callable.policy, callable.input, callable.fields, !callable.static, `/closure/${entryIndex}/definitions/classes/${classIndex}/methods/${methodIndex}/policy`);
33
+ }
34
+ }
35
+ }
36
+ }
37
+ function validatePolicyCycles(entry, local, entryIndex) {
38
+ const visiting = new Set();
39
+ const visited = new Set();
40
+ const visit = (name) => {
41
+ if (visiting.has(name))
42
+ fail(`/closure/${entryIndex}/definitions/policies`, `Named Policy composition cycle reaches ${name}.`);
43
+ if (visited.has(name))
44
+ return;
45
+ visiting.add(name);
46
+ const expression = local.get(name)?.expression;
47
+ if (expression !== undefined && !('match' in expression)) {
48
+ for (const ref of 'allOf' in expression ? expression.allOf : expression.anyOf)
49
+ if (ref.origin === entry.origin && ref.kind === 'policy')
50
+ visit(ref.name);
51
+ }
52
+ visiting.delete(name);
53
+ visited.add(name);
54
+ };
55
+ for (const name of local.keys())
56
+ visit(name);
57
+ }
@@ -0,0 +1,5 @@
1
+ import { type PolicyCheckExpression } from '../../../../language/policy/model/policy.js';
2
+ import { type CompiledSchemaEntry } from '../../../model/schema.js';
3
+ import { type SemanticIndex } from '../context.js';
4
+ /** Check callable Policy references, receiver access and input Path placement. */
5
+ export declare function validateCallablePolicy(context: SemanticIndex, entry: CompiledSchemaEntry, expression: PolicyCheckExpression, inputIndex: number, fields: Readonly<Record<string, readonly number[]>> | undefined, instanceMethod: boolean, path: string): void;
@@ -0,0 +1,72 @@
1
+ import { Key } from '../../../../addressing/index.js';
2
+ import {} from '../../../../language/policy/model/policy.js';
3
+ import { GRAPH_NODE_PATH_SCHEMA_ID } from '../../../../language/value/syntax/node-path/schema.js';
4
+ import {} from '../../../model/schema.js';
5
+ import { fail } from '../../diagnostic.js';
6
+ import {} from '../context.js';
7
+ import { validatePolicyMethod } from './pattern.js';
8
+ /** Check callable Policy references, receiver access and input Path placement. */
9
+ export function validateCallablePolicy(context, entry, expression, inputIndex, fields, instanceMethod, path) {
10
+ if ('check' in expression || 'sameNode' in expression) {
11
+ if ('check' in expression &&
12
+ (expression.check.origin !== entry.origin ||
13
+ context.policies.get(Key.of(expression.check)) === undefined))
14
+ fail(`${path}/check`, 'Callable Policy must reference a local named Policy.');
15
+ const objects = 'check' in expression ? { object: expression.object } : expression.sameNode;
16
+ for (const [side, object] of Object.entries(objects)) {
17
+ if (object.kind === 'ref' && object.ref.kind === 'method')
18
+ validatePolicyMethod(context, object.ref, `${path}/${side}/ref`);
19
+ if (object.kind === 'self' && !instanceMethod)
20
+ fail(`${path}/${side}`, 'self is valid only for an instance Method.');
21
+ if (object.kind === 'input' &&
22
+ (fields === undefined ||
23
+ fields[object.field] === undefined ||
24
+ !isSingleNodePathField(context, entry, inputIndex, object.field))) {
25
+ fail(`${path}/${side}`, 'Callable Policy input target must be a direct required single-Node Path field.');
26
+ }
27
+ }
28
+ return;
29
+ }
30
+ const children = 'allOf' in expression ? expression.allOf : expression.anyOf;
31
+ if (children.length === 0)
32
+ fail(path, 'Callable Policy composition must be non-empty.');
33
+ children.forEach((child, index) => validateCallablePolicy(context, entry, child, inputIndex, fields, instanceMethod, `${path}/${index}`));
34
+ }
35
+ function isSingleNodePathField(context, entry, inputIndex, field) {
36
+ const rootValue = entry.values[inputIndex]?.nodes[entry.values[inputIndex].root]?.schema;
37
+ if (rootValue === null || typeof rootValue !== 'object' || Array.isArray(rootValue))
38
+ return false;
39
+ const root = rootValue;
40
+ const properties = root.properties;
41
+ if (properties === null || typeof properties !== 'object' || Array.isArray(properties))
42
+ return false;
43
+ const schemaValue = properties[field];
44
+ if (schemaValue === null || typeof schemaValue !== 'object' || Array.isArray(schemaValue))
45
+ return false;
46
+ const schema = schemaValue;
47
+ const annotationValue = schema['x-astrale-path'];
48
+ if (annotationValue === null ||
49
+ typeof annotationValue !== 'object' ||
50
+ Array.isArray(annotationValue))
51
+ return false;
52
+ const annotation = annotationValue;
53
+ return (root.type === 'object' &&
54
+ root.additionalProperties === false &&
55
+ Array.isArray(root.required) &&
56
+ root.required.includes(field) &&
57
+ schema.$ref === GRAPH_NODE_PATH_SCHEMA_ID &&
58
+ annotation.target === 'node' &&
59
+ annotation.cardinality === 'one' &&
60
+ Array.isArray(annotation.accepts) &&
61
+ annotation.accepts.length > 0 &&
62
+ annotation.accepts.every((ref) => isNodeClassRef(context, ref)));
63
+ }
64
+ function isNodeClassRef(context, value) {
65
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
66
+ return false;
67
+ const ref = value;
68
+ if (typeof ref.origin !== 'string' || ref.kind !== 'class' || typeof ref.name !== 'string') {
69
+ return false;
70
+ }
71
+ return context.classes.get(Key.of(ref))?.value.kind === 'node';
72
+ }
@@ -0,0 +1,24 @@
1
+ import type { PolicyCheckObject } from '../../../../language/policy/model/policy.js';
2
+ import { type ClassRef } from '../../../../addressing/index.js';
3
+ import { type CompiledSchemaEntry } from '../../../model/schema.js';
4
+ import { type SemanticIndex } from '../context.js';
5
+ /** The default protected object contract or one exact Class. */
6
+ export type CompiledObjectContract = {
7
+ readonly kind: 'default';
8
+ } | {
9
+ readonly kind: 'exact';
10
+ readonly ref: ClassRef;
11
+ };
12
+ /** The protected object or endpoint contracts of one Policy use. */
13
+ export type CompiledPolicyUse = {
14
+ readonly kind: 'object';
15
+ readonly object: CompiledObjectContract;
16
+ } | {
17
+ readonly kind: 'edge';
18
+ readonly source: CompiledObjectContract;
19
+ readonly target: CompiledObjectContract;
20
+ };
21
+ /** Resolve callable Policy objects to their protected Class contracts. */
22
+ export declare function callableObjectContracts(context: SemanticIndex, entry: CompiledSchemaEntry, input: number, receiver: ClassRef | undefined, object: PolicyCheckObject): readonly CompiledObjectContract[] | undefined;
23
+ /** Select the protected contract for an object or Edge endpoint term. */
24
+ export declare function compiledTargetContract(term: string, use: CompiledPolicyUse): CompiledObjectContract | undefined;
@@ -0,0 +1,45 @@
1
+ import { Key } from '../../../../addressing/index.js';
2
+ import {} from '../../../model/schema.js';
3
+ import {} from '../context.js';
4
+ /** Resolve callable Policy objects to their protected Class contracts. */
5
+ export function callableObjectContracts(context, entry, input, receiver, object) {
6
+ if (object.kind === 'self') {
7
+ return receiver === undefined ? undefined : [{ kind: 'exact', ref: receiver }];
8
+ }
9
+ if (object.kind === 'input') {
10
+ return nodePathAccepts(entry, input, object.field).map((ref) => ({ kind: 'exact', ref }));
11
+ }
12
+ const ref = object.ref;
13
+ if (ref.kind === 'core') {
14
+ const node = context.core.get(Key.of(ref))?.value;
15
+ return node === undefined ? undefined : [{ kind: 'exact', ref: node.class }];
16
+ }
17
+ const projection = ref.kind === 'class'
18
+ ? 'Class'
19
+ : ref.kind === 'function' || ref.kind === 'method'
20
+ ? 'Function'
21
+ : ref.kind === 'policy'
22
+ ? 'Policy'
23
+ : 'View';
24
+ return [
25
+ {
26
+ kind: 'exact',
27
+ ref: { origin: 'kernel.astrale.ai', kind: 'class', name: projection },
28
+ },
29
+ ];
30
+ }
31
+ function nodePathAccepts(entry, input, field) {
32
+ const root = entry.values[input]?.nodes[entry.values[input].root]?.schema;
33
+ const properties = root?.properties;
34
+ const fieldSchema = properties?.[field];
35
+ const annotation = fieldSchema?.['x-astrale-path'];
36
+ return Array.isArray(annotation?.accepts)
37
+ ? annotation.accepts
38
+ : [];
39
+ }
40
+ /** Select the protected contract for an object or Edge endpoint term. */
41
+ export function compiledTargetContract(term, use) {
42
+ if (use.kind === 'object')
43
+ return term === 'object' ? use.object : undefined;
44
+ return term === 'source' ? use.source : term === 'target' ? use.target : undefined;
45
+ }
@@ -0,0 +1,8 @@
1
+ /** Retain and merge term equalities while typing one Policy branch. */
2
+ export declare class CompiledUnionFind {
3
+ #private;
4
+ constructor(values: Iterable<string>);
5
+ add(value: string): void;
6
+ find(value: string): string;
7
+ join(left: string, right: string): void;
8
+ }
@@ -0,0 +1,27 @@
1
+ /** Retain and merge term equalities while typing one Policy branch. */
2
+ export class CompiledUnionFind {
3
+ #parents = new Map();
4
+ constructor(values) {
5
+ for (const value of values)
6
+ this.add(value);
7
+ }
8
+ add(value) {
9
+ if (!this.#parents.has(value))
10
+ this.#parents.set(value, value);
11
+ }
12
+ find(value) {
13
+ this.add(value);
14
+ const parent = this.#parents.get(value);
15
+ if (parent === value)
16
+ return value;
17
+ const root = this.find(parent);
18
+ this.#parents.set(value, root);
19
+ return root;
20
+ }
21
+ join(left, right) {
22
+ const a = this.find(left);
23
+ const b = this.find(right);
24
+ if (a !== b)
25
+ this.#parents.set(b, a);
26
+ }
27
+ }
@@ -0,0 +1,9 @@
1
+ import { type PolicyExpression } from '../../../../language/policy/model/policy.js';
2
+ interface CompiledPatternMeasure {
3
+ readonly depth: number;
4
+ readonly edgeCounts: readonly number[];
5
+ readonly domains: ReadonlySet<string>;
6
+ }
7
+ /** Measure expanded Policy branches, depth and referenced Domains. */
8
+ export declare function measureCompiledPolicy(origin: string, name: string, normalized: ReadonlyMap<string, PolicyExpression>, visiting: Set<string>): CompiledPatternMeasure | undefined;
9
+ export {};
@@ -0,0 +1,81 @@
1
+ import { policyObjectOrigin, policyVariableClass } from '../../../../language/index.js';
2
+ import { BRANCH_OVERFLOW } from '../../../../language/policy/analysis/budgets.js';
3
+ import {} from '../../../../language/policy/model/policy.js';
4
+ /** Measure expanded Policy branches, depth and referenced Domains. */
5
+ export function measureCompiledPolicy(origin, name, normalized, visiting) {
6
+ if (visiting.has(name))
7
+ return undefined;
8
+ const expression = normalized.get(name);
9
+ if (expression === undefined)
10
+ return undefined;
11
+ if ('match' in expression)
12
+ return measureCompiledPattern(expression.match, origin);
13
+ const nested = new Set(visiting);
14
+ nested.add(name);
15
+ const refs = 'allOf' in expression ? expression.allOf : expression.anyOf;
16
+ const children = refs.map((ref) => ref.origin === origin ? measureCompiledPolicy(origin, ref.name, normalized, nested) : undefined);
17
+ if (children.some((value) => value === undefined))
18
+ return undefined;
19
+ return combineCompiledMeasures('allOf' in expression ? 'allOf' : 'anyOf', children);
20
+ }
21
+ function measureCompiledPattern(pattern, origin) {
22
+ if ('sameNode' in pattern)
23
+ return {
24
+ depth: 1,
25
+ edgeCounts: [1],
26
+ domains: new Set([
27
+ origin,
28
+ ...[pattern.sameNode.left, pattern.sameNode.right].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
29
+ ]),
30
+ };
31
+ if ('source' in pattern)
32
+ return {
33
+ depth: 1,
34
+ edgeCounts: [1],
35
+ domains: new Set([
36
+ origin,
37
+ pattern.class.origin,
38
+ ...[pattern.source, pattern.target].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
39
+ ]),
40
+ };
41
+ if ('exists' in pattern) {
42
+ const child = measureCompiledPattern(pattern.exists.where, origin);
43
+ return {
44
+ depth: child.depth + 1,
45
+ edgeCounts: child.edgeCounts,
46
+ domains: new Set([
47
+ ...child.domains,
48
+ ...pattern.exists.nodes.flatMap((node) => {
49
+ const ref = policyVariableClass(node);
50
+ return ref === undefined ? [] : [ref.origin];
51
+ }),
52
+ ]),
53
+ };
54
+ }
55
+ return combineCompiledMeasures('allOf' in pattern ? 'allOf' : 'anyOf', ('allOf' in pattern ? pattern.allOf : pattern.anyOf).map((child) => measureCompiledPattern(child, origin)));
56
+ }
57
+ function combineCompiledMeasures(kind, children) {
58
+ const depth = 1 + Math.max(0, ...children.map((child) => child.depth));
59
+ const domains = new Set(children.flatMap((child) => [...child.domains]));
60
+ if (kind === 'anyOf')
61
+ return {
62
+ depth,
63
+ edgeCounts: children.flatMap((child) => child.edgeCounts).slice(0, BRANCH_OVERFLOW),
64
+ domains,
65
+ };
66
+ let edgeCounts = [0];
67
+ for (const child of children) {
68
+ const next = [];
69
+ for (const left of edgeCounts) {
70
+ for (const right of child.edgeCounts) {
71
+ next.push(left + right);
72
+ if (next.length >= BRANCH_OVERFLOW)
73
+ break;
74
+ }
75
+ if (next.length >= BRANCH_OVERFLOW)
76
+ break;
77
+ }
78
+ edgeCounts = next;
79
+ }
80
+ return { depth, edgeCounts, domains };
81
+ }
@@ -0,0 +1,4 @@
1
+ import { type CompiledSchemaEntry } from '../../../model/schema.js';
2
+ import { type SemanticIndex, type CompiledPolicy } from '../context.js';
3
+ /** Check Policy typing and expansion budgets against the entry’s own closure. */
4
+ export declare function validatePolicyParity(context: SemanticIndex, entry: CompiledSchemaEntry, entryIndex: number, policies: ReadonlyMap<string, CompiledPolicy>, origins: ReadonlySet<string>): void;