@astrale-os/kernel-dsl 1.0.0-beta.12 → 1.0.0-beta.13
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.
- package/dist/v1/addressing/definition-ref.js +21 -37
- package/dist/v1/addressing/ordering.d.ts +2 -0
- package/dist/v1/addressing/ordering.js +4 -0
- package/dist/v1/addressing/patterns.d.ts +0 -1
- package/dist/v1/addressing/patterns.js +0 -5
- package/dist/v1/builder/class/authoring.js +5 -28
- package/dist/v1/builder/lowering/schema/context.js +2 -4
- package/dist/v1/builder/lowering/value/path.js +2 -4
- package/dist/v1/builder/lowering/value/zod.js +1 -3
- package/dist/v1/builder/schema/define.d.ts +0 -1
- package/dist/v1/builder/schema/diagnostic.d.ts +2 -1
- package/dist/v1/builder/schema/diagnostic.js +5 -10
- package/dist/v1/builder/schema/projection.d.ts +1 -1
- package/dist/v1/builder/value/full-match.d.ts +0 -1
- package/dist/v1/builder/value/full-match.js +0 -1
- package/dist/v1/bundle/codec.js +2 -4
- package/dist/v1/bundle/diagnostic.js +3 -7
- package/dist/v1/bundle/structure.js +2 -4
- package/dist/v1/compiled/admission/diagnostic.d.ts +1 -1
- package/dist/v1/compiled/admission/diagnostic.js +1 -3
- package/dist/v1/compiled/admission/revision.d.ts +9 -1
- package/dist/v1/compiled/admission/revision.js +6 -3
- package/dist/v1/compiled/admission/semantics/class.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/class.js +4 -8
- package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
- package/dist/v1/compiled/admission/semantics/core.js +54 -34
- package/dist/v1/compiled/admission/semantics/edge.d.ts +2 -4
- package/dist/v1/compiled/admission/semantics/edge.js +6 -65
- package/dist/v1/compiled/admission/semantics/policy/callable.js +0 -2
- package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +5 -20
- package/dist/v1/compiled/admission/semantics/policy/contracts.js +8 -21
- package/dist/v1/compiled/admission/semantics/policy/parity.js +13 -22
- package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +4 -1
- package/dist/v1/compiled/admission/semantics/policy/pattern.js +4 -16
- package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +2 -24
- package/dist/v1/compiled/admission/semantics/policy/typing.js +19 -201
- package/dist/v1/compiled/compiler/compile.js +6 -8
- package/dist/v1/compiled/diagnostic.js +2 -3
- package/dist/v1/compiled/loader/load.d.ts +3 -2
- package/dist/v1/compiled/loader/load.js +10 -44
- package/dist/v1/domain/create.js +3 -5
- package/dist/v1/domain/namespace/member-collection.js +4 -6
- package/dist/v1/domain/validation/create.d.ts +0 -1
- package/dist/v1/domain/validation/create.js +0 -35
- package/dist/v1/language/class/inheritance.d.ts +18 -0
- package/dist/v1/language/class/inheritance.js +73 -0
- package/dist/v1/language/class/property-values.js +2 -4
- package/dist/v1/language/core/facts.d.ts +72 -0
- package/dist/v1/language/core/facts.js +95 -0
- package/dist/v1/language/policy/analysis/branches.d.ts +8 -0
- package/dist/v1/language/policy/analysis/branches.js +2 -1
- package/dist/v1/language/policy/analysis/budgets.d.ts +13 -1
- package/dist/v1/language/policy/analysis/budgets.js +104 -0
- package/dist/v1/language/policy/analysis/typing.d.ts +48 -0
- package/dist/v1/language/policy/analysis/typing.js +338 -0
- package/dist/v1/language/validation/diagnostic.d.ts +14 -0
- package/dist/v1/language/validation/diagnostic.js +21 -0
- package/dist/v1/language/value/compile/fields.js +4 -8
- package/dist/v1/language/value/profile/rules.js +5 -7
- package/dist/v1/language/value/profile/validate.js +1 -10
- package/dist/v1/language/value/reference/recursion.js +2 -22
- package/dist/v1/language/value/syntax/pointer.d.ts +2 -0
- package/dist/v1/language/value/syntax/pointer.js +5 -2
- package/dist/v1/language/value/syntax/walk.d.ts +2 -0
- package/dist/v1/language/value/syntax/walk.js +19 -20
- package/dist/v1/schema/compatibility/diff.js +2 -4
- package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
- package/dist/v1/schema/compatibility/structure/requirements.js +26 -58
- package/dist/v1/schema/compatibility/walk.d.ts +17 -0
- package/dist/v1/schema/compatibility/walk.js +41 -0
- package/dist/v1/schema/diagnostic.js +3 -11
- package/dist/v1/schema/resolution/context.js +3 -5
- package/dist/v1/schema/validation/callable.js +3 -5
- package/dist/v1/schema/validation/class.js +10 -52
- package/dist/v1/schema/validation/core.js +65 -199
- package/dist/v1/schema/validation/domain.js +1 -10
- package/dist/v1/schema/validation/domain.structure.js +2 -4
- package/dist/v1/schema/validation/policy/budgets.js +5 -112
- package/dist/v1/schema/validation/policy/context.d.ts +5 -3
- package/dist/v1/schema/validation/policy/context.js +5 -3
- package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
- package/dist/v1/schema/validation/policy/objects.js +6 -14
- package/dist/v1/schema/validation/policy/references.js +5 -6
- package/dist/v1/schema/validation/policy/typing.d.ts +3 -18
- package/dist/v1/schema/validation/policy/typing.js +22 -356
- package/dist/v1/schema/validation/policy/uses.d.ts +1 -1
- package/dist/v1/schema/validation/policy/uses.js +9 -22
- package/dist/v1/schema/validation/policy/validate.js +3 -2
- package/dist/v1/schema/validation/value-api.js +2 -2
- package/dist/v1/schema/validation/value.js +5 -7
- package/dist/v1/schema/validation/view.js +4 -8
- package/package.json +1 -1
- package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
- package/dist/v1/compiled/admission/semantics/cardinality.js +0 -128
- package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
- package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
- package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
- package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
- package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
- package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
- package/dist/v1/language/class/index.d.ts +0 -8
- package/dist/v1/language/class/index.js +0 -1
- package/dist/v1/language/core/index.d.ts +0 -2
- package/dist/v1/language/core/index.js +0 -1
- package/dist/v1/language/value/index.d.ts +0 -11
- package/dist/v1/language/value/index.js +0 -8
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { Key } from '../../../addressing/index.js';
|
|
2
2
|
import { isMethodExecutable } from '../../../language/callable/executable.js';
|
|
3
|
-
import { coveringNodeUniqueTuples, nodeUniqueKeys } from '../../../language/class/unique.js';
|
|
3
|
+
import { coveringEdgeUniqueTuples, coveringNodeUniqueTuples, edgeUniqueKeys, nodeUniqueKeys, } from '../../../language/class/unique.js';
|
|
4
|
+
import { checkCoreEdgeSet, checkHeldKeys, coreEndpointsSatisfy, } from '../../../language/core/facts.js';
|
|
4
5
|
import {} from '../../../language/core/model/core.js';
|
|
5
6
|
import { policyObjectOrigin, policyObjectKey, projectedMemberClass, } from '../../../language/index.js';
|
|
6
7
|
import { bindValueProgram } from '../../../language/value/compile/load.js';
|
|
7
8
|
import { validateValueProgram } from '../../../language/value/evaluate/program.js';
|
|
9
|
+
import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
|
|
8
10
|
import {} from '../../model/schema.js';
|
|
9
11
|
import { fail } from '../diagnostic.js';
|
|
10
|
-
import { validateCoreEdgeSet } from './cardinality.js';
|
|
11
12
|
import { isCompiledEdge, classSatisfiesAny, } from './context.js';
|
|
13
|
+
import { sameIncidentEndpoint } from './edge.js';
|
|
12
14
|
/** Admit local Core Nodes, Properties and Edge endpoint contracts. */
|
|
13
15
|
export function validateCore(candidate, context) {
|
|
16
|
+
const resolve = (ref) => context.classes.get(Key.of(ref))?.value;
|
|
14
17
|
for (const [entryIndex, entry] of candidate.closure.entries()) {
|
|
15
18
|
const nodes = new Map();
|
|
16
19
|
for (const [index, value] of entry.definitions.core.entries()) {
|
|
@@ -32,7 +35,9 @@ export function validateCore(candidate, context) {
|
|
|
32
35
|
pointer: path,
|
|
33
36
|
});
|
|
34
37
|
}
|
|
35
|
-
|
|
38
|
+
checkHeldKeys(nodes.values(), (node) => nodeUniqueKeys(coveringNodeUniqueTuples(node.class.value, resolve), {
|
|
39
|
+
props: node.value.properties,
|
|
40
|
+
}), (node) => fail(node.pointer, 'Core Node holds a key another Core Node holds.'));
|
|
36
41
|
const edges = [];
|
|
37
42
|
for (const [index, value] of entry.facts.core.entries()) {
|
|
38
43
|
const path = `/closure/${entryIndex}/facts/core/${index}`;
|
|
@@ -48,14 +53,7 @@ export function validateCore(candidate, context) {
|
|
|
48
53
|
validateCoreProperties(value.properties, analysis, `${path}/properties`);
|
|
49
54
|
const source = resolveCoreEndpoint(context, entry, value.source, nodes, `${path}/source`);
|
|
50
55
|
const target = resolveCoreEndpoint(context, entry, value.target, nodes, `${path}/target`);
|
|
51
|
-
const
|
|
52
|
-
const satisfies = declaration.orientation === 'directed'
|
|
53
|
-
? endpointSatisfies(context, source, declaration.endpoints.source.accepts) &&
|
|
54
|
-
endpointSatisfies(context, target, declaration.endpoints.target.accepts)
|
|
55
|
-
: (endpointSatisfies(context, source, declaration.endpoints[0].accepts) &&
|
|
56
|
-
endpointSatisfies(context, target, declaration.endpoints[1].accepts)) ||
|
|
57
|
-
(endpointSatisfies(context, source, declaration.endpoints[1].accepts) &&
|
|
58
|
-
endpointSatisfies(context, target, declaration.endpoints[0].accepts));
|
|
56
|
+
const satisfies = coreEndpointsSatisfy(classValue.value, source, target, (endpoint, accepts) => endpointSatisfies(context, endpoint, accepts));
|
|
59
57
|
if (!satisfies)
|
|
60
58
|
fail(path, 'Core Edge endpoints do not satisfy its exact Class.');
|
|
61
59
|
edges.push({
|
|
@@ -66,37 +64,61 @@ export function validateCore(candidate, context) {
|
|
|
66
64
|
pointer: path,
|
|
67
65
|
});
|
|
68
66
|
}
|
|
69
|
-
|
|
67
|
+
checkCoreEdgeSet({
|
|
68
|
+
edges: edges.map((edge) => ({
|
|
69
|
+
edge,
|
|
70
|
+
class: Key.of(edge.value.class),
|
|
71
|
+
contract: edge.class.value,
|
|
72
|
+
source: edge.source,
|
|
73
|
+
target: edge.target,
|
|
74
|
+
})),
|
|
75
|
+
classes: entry.definitions.classes
|
|
76
|
+
.filter(isCompiledEdge)
|
|
77
|
+
.map((value) => ({ key: Key.of(value.ref), contract: value })),
|
|
78
|
+
nodes: [...nodes.values()].map(({ key, value, pointer }) => ({
|
|
79
|
+
key,
|
|
80
|
+
class: value.class,
|
|
81
|
+
pointer,
|
|
82
|
+
})),
|
|
83
|
+
satisfies: (ref, accepts) => classSatisfiesAny(context, ref, accepts),
|
|
84
|
+
keys: ({ edge }) => edgeUniqueKeys(coveringEdgeUniqueTuples(edge.class.value, resolve), {
|
|
85
|
+
source: edge.source.key,
|
|
86
|
+
target: edge.target.key,
|
|
87
|
+
props: edge.value.properties,
|
|
88
|
+
}),
|
|
89
|
+
sameIncident: sameIncidentEndpoint,
|
|
90
|
+
report: (issue) => coreEdgeFailure(issue, entryIndex),
|
|
91
|
+
});
|
|
70
92
|
}
|
|
71
93
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
fail(
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
function coreEdgeFailure(issue, entryIndex) {
|
|
95
|
+
switch (issue.kind) {
|
|
96
|
+
case 'identity':
|
|
97
|
+
return fail(issue.edge.pointer, 'Core Edge duplicates an exact normalized Edge identity.');
|
|
98
|
+
case 'no-self':
|
|
99
|
+
return fail(issue.edge.pointer, 'Core Edge violates noSelf.');
|
|
100
|
+
case 'key':
|
|
101
|
+
return fail(issue.edge.pointer, 'Core Edge holds a key another Core Edge holds.');
|
|
102
|
+
case 'acyclic':
|
|
103
|
+
return fail(`/closure/${entryIndex}/facts/core`, 'Core Edge set violates exact-Class acyclicity.');
|
|
104
|
+
case 'degree':
|
|
105
|
+
return fail(issue.pointer, `Core degree ${issue.degree} violates Edge count ${issue.count}.`);
|
|
84
106
|
}
|
|
85
107
|
}
|
|
86
108
|
function validateCoreProperties(values, analysis, path) {
|
|
87
109
|
for (const key of Object.keys(values))
|
|
88
110
|
if (!analysis.properties.has(key))
|
|
89
|
-
fail(`${path}/${
|
|
111
|
+
fail(`${path}/${escapePointerToken(key)}`, 'Core properties contain an unknown Property key.');
|
|
90
112
|
for (const property of analysis.properties.values()) {
|
|
91
113
|
if (!Object.hasOwn(values, property.key)) {
|
|
92
114
|
if (property.declaration.required && property.declaration.auto === undefined)
|
|
93
|
-
fail(`${path}/${
|
|
115
|
+
fail(`${path}/${escapePointerToken(property.key)}`, 'Core properties omit a required Property.');
|
|
94
116
|
continue;
|
|
95
117
|
}
|
|
96
118
|
if (property.declaration.auto !== undefined)
|
|
97
|
-
fail(`${path}/${
|
|
119
|
+
fail(`${path}/${escapePointerToken(property.key)}`, 'Core properties cannot author an automatic Property.');
|
|
98
120
|
if (validateValueProgram(bindValueProgram(property.entry.values[property.declaration.value], property.entry.patterns), values[property.key]).length > 0)
|
|
99
|
-
fail(`${path}/${
|
|
121
|
+
fail(`${path}/${escapePointerToken(property.key)}`, 'Core Property value does not satisfy its exact contract.');
|
|
100
122
|
}
|
|
101
123
|
}
|
|
102
124
|
function resolveCoreEndpoint(context, entry, ref, nodes, path) {
|
|
@@ -109,7 +131,8 @@ function resolveCoreEndpoint(context, entry, ref, nodes, path) {
|
|
|
109
131
|
return nodes.get(Key.of(ref)) ?? undeclared();
|
|
110
132
|
if (!declaresProjectedMember(context, entry, ref))
|
|
111
133
|
return undeclared();
|
|
112
|
-
|
|
134
|
+
// A projected member's degree is reported at the endpoint that names it.
|
|
135
|
+
return { key: policyObjectKey(ref), member: { class: projectedMemberClass(ref), pointer: path } };
|
|
113
136
|
}
|
|
114
137
|
/** Only a projected declaration can carry a Core fact; an abstract Method is never projected. */
|
|
115
138
|
function declaresProjectedMember(context, entry, ref) {
|
|
@@ -130,10 +153,7 @@ function declaresProjectedMember(context, entry, ref) {
|
|
|
130
153
|
function endpointSatisfies(context, endpoint, accepts) {
|
|
131
154
|
if ('value' in endpoint)
|
|
132
155
|
return classSatisfiesAny(context, endpoint.value.class, accepts);
|
|
133
|
-
if ('
|
|
134
|
-
return classSatisfiesAny(context, endpoint.class, accepts);
|
|
156
|
+
if ('member' in endpoint)
|
|
157
|
+
return classSatisfiesAny(context, endpoint.member.class, accepts);
|
|
135
158
|
return true;
|
|
136
159
|
}
|
|
137
|
-
function escapePointer(value) {
|
|
138
|
-
return value.replaceAll('~', '~0').replaceAll('/', '~1');
|
|
139
|
-
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type IncidentEndpoint } from '../../../language/class/model/edge.js';
|
|
2
2
|
import { type SemanticIndex } from './context.js';
|
|
3
|
-
/** Check Edge
|
|
3
|
+
/** Check safe Edge inheritance refinement; the wire and closure checks own the endpoints. */
|
|
4
4
|
export declare function validateEdges(context: SemanticIndex): void;
|
|
5
5
|
/** Compare undirected endpoint acceptance and cardinality contracts. */
|
|
6
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];
|
|
@@ -1,71 +1,25 @@
|
|
|
1
1
|
import { Key } from '../../../addressing/index.js';
|
|
2
2
|
import { compareUnicode } from '../../../addressing/ordering.js';
|
|
3
|
-
import {
|
|
3
|
+
import { edgeContractRefines } from '../../../language/class/inheritance.js';
|
|
4
4
|
import {} from '../../../language/class/model/edge.js';
|
|
5
5
|
import { fail } from '../diagnostic.js';
|
|
6
|
-
import { isCompiledEdge, classSatisfiesAny
|
|
7
|
-
/** Check Edge
|
|
6
|
+
import { isCompiledEdge, classSatisfiesAny } from './context.js';
|
|
7
|
+
/** Check safe Edge inheritance refinement; the wire and closure checks own the endpoints. */
|
|
8
8
|
export function validateEdges(context) {
|
|
9
9
|
for (const located of context.classes.values()) {
|
|
10
10
|
if (!isCompiledEdge(located.value))
|
|
11
11
|
continue;
|
|
12
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
13
|
for (const [parentIndex, parentRef] of edge.extends.entries()) {
|
|
30
14
|
const parent = context.classes.get(Key.of(parentRef))?.value;
|
|
31
|
-
if (parent !== undefined &&
|
|
15
|
+
if (parent !== undefined &&
|
|
16
|
+
isCompiledEdge(parent) &&
|
|
17
|
+
!edgeContractRefines(edge, parent, (candidate, accepts) => classSatisfiesAny(context, candidate, accepts))) {
|
|
32
18
|
fail(`${located.pointer}/extends/${parentIndex}`, 'Edge Class does not safely refine its parent.');
|
|
33
19
|
}
|
|
34
20
|
}
|
|
35
21
|
}
|
|
36
22
|
}
|
|
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
23
|
/** Compare undirected endpoint acceptance and cardinality contracts. */
|
|
70
24
|
export function sameIncidentEndpoint(left, right) {
|
|
71
25
|
const a = left.accepts.map(Key.of).sort(compareUnicode);
|
|
@@ -74,16 +28,3 @@ export function sameIncidentEndpoint(left, right) {
|
|
|
74
28
|
a.length === b.length &&
|
|
75
29
|
a.every((value, index) => value === b[index]));
|
|
76
30
|
}
|
|
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
|
-
}
|
|
@@ -28,8 +28,6 @@ export function validateCallablePolicy(context, entry, expression, inputIndex, f
|
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
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
31
|
children.forEach((child, index) => validateCallablePolicy(context, entry, child, inputIndex, fields, instanceMethod, `${path}/${index}`));
|
|
34
32
|
}
|
|
35
33
|
function isSingleNodePathField(context, entry, inputIndex, field) {
|
|
@@ -1,24 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ObjectContract } from '../../../../language/policy/analysis/typing.js';
|
|
2
2
|
import { type ClassRef } from '../../../../addressing/index.js';
|
|
3
|
+
import { type PolicyCheckObject, type PolicyObjectRef } from '../../../../language/policy/model/policy.js';
|
|
3
4
|
import { type CompiledSchemaEntry } from '../../../model/schema.js';
|
|
4
5
|
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
6
|
/** 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
|
|
23
|
-
/**
|
|
24
|
-
export declare function
|
|
7
|
+
export declare function callableObjectContracts(context: SemanticIndex, entry: CompiledSchemaEntry, input: number, receiver: ClassRef | undefined, object: PolicyCheckObject): readonly ObjectContract[] | undefined;
|
|
8
|
+
/** Resolve a referenced Policy object to its protected Class contract. */
|
|
9
|
+
export declare function referenceContract(context: SemanticIndex, ref: PolicyObjectRef): ObjectContract | undefined;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Key } from '../../../../addressing/index.js';
|
|
2
|
+
import { projectedMemberClass, } from '../../../../language/policy/model/policy.js';
|
|
2
3
|
import {} from '../../../model/schema.js';
|
|
3
4
|
import {} from '../context.js';
|
|
4
5
|
/** Resolve callable Policy objects to their protected Class contracts. */
|
|
@@ -9,24 +10,16 @@ export function callableObjectContracts(context, entry, input, receiver, object)
|
|
|
9
10
|
if (object.kind === 'input') {
|
|
10
11
|
return nodePathAccepts(entry, input, object.field).map((ref) => ({ kind: 'exact', ref }));
|
|
11
12
|
}
|
|
12
|
-
const
|
|
13
|
+
const contract = referenceContract(context, object.ref);
|
|
14
|
+
return contract === undefined ? undefined : [contract];
|
|
15
|
+
}
|
|
16
|
+
/** Resolve a referenced Policy object to its protected Class contract. */
|
|
17
|
+
export function referenceContract(context, ref) {
|
|
13
18
|
if (ref.kind === 'core') {
|
|
14
19
|
const node = context.core.get(Key.of(ref))?.value;
|
|
15
|
-
return node === undefined ? undefined :
|
|
20
|
+
return node === undefined ? undefined : { kind: 'exact', ref: node.class };
|
|
16
21
|
}
|
|
17
|
-
|
|
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
|
-
];
|
|
22
|
+
return { kind: 'exact', ref: projectedMemberClass(ref) };
|
|
30
23
|
}
|
|
31
24
|
function nodePathAccepts(entry, input, field) {
|
|
32
25
|
const root = entry.values[input]?.nodes[entry.values[input].root]?.schema;
|
|
@@ -37,9 +30,3 @@ function nodePathAccepts(entry, input, field) {
|
|
|
37
30
|
? annotation.accepts
|
|
38
31
|
: [];
|
|
39
32
|
}
|
|
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
|
-
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {} from '../../../../language/class/model/edge.js';
|
|
1
|
+
import {} from '../../../../addressing/index.js';
|
|
3
2
|
import { branchesOf, targetMode, isConnected, } from '../../../../language/policy/analysis/branches.js';
|
|
4
|
-
import { MAX_PATTERN_DEPTH, MAX_BRANCHES, MAX_EDGES, MAX_DOMAINS, measureChecks, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, } from '../../../../language/policy/analysis/budgets.js';
|
|
5
|
-
import {
|
|
3
|
+
import { MAX_PATTERN_DEPTH, MAX_BRANCHES, MAX_EDGES, MAX_DOMAINS, measureChecks, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, policyMeasurer, } from '../../../../language/policy/analysis/budgets.js';
|
|
4
|
+
import { neverAdmittedClasses, } from '../../../../language/policy/analysis/checks.js';
|
|
5
|
+
import {} from '../../../../language/policy/analysis/typing.js';
|
|
6
6
|
import { checksNameTheCaller, isClassRuleChecks, } from '../../../../language/policy/model/policy.js';
|
|
7
7
|
import { normalizePolicyExpression } from '../../../../language/policy/normalization/normalize.js';
|
|
8
8
|
import {} from '../../../model/schema.js';
|
|
9
9
|
import { fail } from '../../diagnostic.js';
|
|
10
10
|
import { isCompiledEdge } from '../context.js';
|
|
11
11
|
import { callableObjectContracts } from './contracts.js';
|
|
12
|
-
import {
|
|
13
|
-
import { CompiledPolicyTyping } from './typing.js';
|
|
12
|
+
import { compiledPolicyTyping } from './typing.js';
|
|
14
13
|
/** Check Policy typing and expansion budgets against the entry’s own closure. */
|
|
15
14
|
export function validatePolicyParity(context, entry, entryIndex, policies, origins) {
|
|
16
15
|
const normalized = new Map([...policies].map(([name, policy]) => [name, normalizePolicyExpression(policy.expression)]));
|
|
17
|
-
const typing =
|
|
16
|
+
const typing = compiledPolicyTyping(context, entry, normalized, origins);
|
|
17
|
+
const measurePolicy = policyMeasurer(entry.origin, normalized, (ref) => ref.origin === entry.origin);
|
|
18
18
|
for (const [name, declaration] of policies) {
|
|
19
19
|
const path = `/closure/${entryIndex}/definitions/policies/${declarationIndex(entry, 'policies', name)}`;
|
|
20
20
|
if ('match' in declaration.expression) {
|
|
@@ -27,7 +27,7 @@ export function validatePolicyParity(context, entry, entryIndex, policies, origi
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
const measure =
|
|
30
|
+
const measure = measurePolicy(name);
|
|
31
31
|
if (measure !== undefined &&
|
|
32
32
|
(measure.depth > MAX_PATTERN_DEPTH ||
|
|
33
33
|
measure.edgeCounts.length > MAX_BRANCHES ||
|
|
@@ -35,7 +35,7 @@ export function validatePolicyParity(context, entry, entryIndex, policies, origi
|
|
|
35
35
|
measure.domains.size > MAX_DOMAINS)) {
|
|
36
36
|
fail(path, 'Policy expansion exceeds the V1 depth, branch, Edge, or Domain budget.');
|
|
37
37
|
}
|
|
38
|
-
const branches = typing.expandedBranches(name,
|
|
38
|
+
const branches = typing.expandedBranches(name, `$${name}`);
|
|
39
39
|
if (branches !== undefined) {
|
|
40
40
|
for (const branch of branches) {
|
|
41
41
|
const mode = targetMode(branch);
|
|
@@ -67,12 +67,7 @@ export function validatePolicyParity(context, entry, entryIndex, policies, origi
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
else if (isCompiledEdge(definition)) {
|
|
70
|
-
|
|
71
|
-
? [definition.endpoints.source, definition.endpoints.target]
|
|
72
|
-
: definition.endpoints;
|
|
73
|
-
const sources = typing.concreteEndpointClasses(endpoints[0].accepts);
|
|
74
|
-
const targets = typing.concreteEndpointClasses(endpoints[1].accepts);
|
|
75
|
-
if (sources.some((source) => targets.some((target) => !typing.policyAcceptsEdge(policy.name, { kind: 'exact', ref: source }, { kind: 'exact', ref: target })))) {
|
|
70
|
+
if (!typing.policyAcceptsEdgeClass(policy.name, definition)) {
|
|
76
71
|
fail(path, `${label} Policy is incompatible with an accepted Edge endpoint pair.`);
|
|
77
72
|
}
|
|
78
73
|
}
|
|
@@ -121,15 +116,11 @@ function validatePolicyChecks(context, typing, entry, expression, input, receive
|
|
|
121
116
|
const contracts = callableObjectContracts(context, entry, input, receiver, value.object);
|
|
122
117
|
if (contracts === undefined)
|
|
123
118
|
return;
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
typing.policyBranchTyping(value.check.name, contract),
|
|
127
|
-
]));
|
|
128
|
-
const admitted = admittedCheckClasses(typings);
|
|
129
|
-
if (admitted === undefined) {
|
|
119
|
+
const classes = typing.checkLeafClasses(value.check.name, contracts);
|
|
120
|
+
if (classes === undefined) {
|
|
130
121
|
fail(pointer, `Named Policy is incompatible with ${SITE[site].objects}.`);
|
|
131
122
|
}
|
|
132
|
-
leaves.set(value,
|
|
123
|
+
leaves.set(value, classes);
|
|
133
124
|
};
|
|
134
125
|
visit(expression, path);
|
|
135
126
|
const [never] = neverAdmittedClasses(expression, leaves);
|
|
@@ -2,7 +2,10 @@ import { type MethodAddress } from '../../../../addressing/index.js';
|
|
|
2
2
|
import { type PolicyExpression } from '../../../../language/policy/model/policy.js';
|
|
3
3
|
import { type CompiledSchemaEntry } from '../../../model/schema.js';
|
|
4
4
|
import { type SemanticIndex, type CompiledPolicy } from '../context.js';
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Check named Policy composition and scoped pattern references. The wire grammar already bounds
|
|
7
|
+
* repeats and variables and refuses empty compositions.
|
|
8
|
+
*/
|
|
6
9
|
export declare function validatePolicyExpression(context: SemanticIndex, entry: CompiledSchemaEntry, expression: PolicyExpression, path: string, local: ReadonlyMap<string, CompiledPolicy>): void;
|
|
7
10
|
/** Require an exact executable Method declaration for a Policy reference. */
|
|
8
11
|
export declare function validatePolicyMethod(context: SemanticIndex, ref: MethodAddress, path: string): void;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { Key } from '../../../../addressing/index.js';
|
|
2
2
|
import { isMethodExecutable } from '../../../../language/callable/executable.js';
|
|
3
3
|
import { policyVariableClass } from '../../../../language/index.js';
|
|
4
|
-
import { MAX_REPEAT, MAX_VARIABLES } from '../../../../language/policy/analysis/budgets.js';
|
|
5
4
|
import {} from '../../../../language/policy/model/policy.js';
|
|
6
5
|
import {} from '../../../model/schema.js';
|
|
7
6
|
import { fail } from '../../diagnostic.js';
|
|
8
7
|
import {} from '../context.js';
|
|
9
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Check named Policy composition and scoped pattern references. The wire grammar already bounds
|
|
10
|
+
* repeats and variables and refuses empty compositions.
|
|
11
|
+
*/
|
|
10
12
|
export function validatePolicyExpression(context, entry, expression, path, local) {
|
|
11
13
|
if ('match' in expression) {
|
|
12
14
|
validatePattern(context, expression.match, `${path}/match`, new Set(), new Set());
|
|
13
15
|
return;
|
|
14
16
|
}
|
|
15
17
|
const values = 'allOf' in expression ? expression.allOf : expression.anyOf;
|
|
16
|
-
if (values.length === 0)
|
|
17
|
-
fail(path, 'Named Policy composition must be non-empty.');
|
|
18
18
|
for (const [index, ref] of values.entries()) {
|
|
19
19
|
if (ref.origin !== entry.origin || ref.kind !== 'policy' || !local.has(ref.name))
|
|
20
20
|
fail(`${path}/${index}`, 'Named Policy composition must reference a local Policy.');
|
|
@@ -31,19 +31,9 @@ function validatePattern(context, expression, path, scope, declared) {
|
|
|
31
31
|
fail(`${path}/class`, 'Policy pattern Class must resolve to an Edge Class.');
|
|
32
32
|
validatePolicyTerm(context, expression.source, `${path}/source`, scope);
|
|
33
33
|
validatePolicyTerm(context, expression.target, `${path}/target`, scope);
|
|
34
|
-
if (expression.repeat !== undefined &&
|
|
35
|
-
(!Number.isInteger(expression.repeat.min) ||
|
|
36
|
-
!Number.isInteger(expression.repeat.max) ||
|
|
37
|
-
expression.repeat.min < 0 ||
|
|
38
|
-
expression.repeat.max < expression.repeat.min ||
|
|
39
|
-
expression.repeat.max > MAX_REPEAT))
|
|
40
|
-
fail(`${path}/repeat`, 'Policy repeat is outside the V1 bounds.');
|
|
41
34
|
return;
|
|
42
35
|
}
|
|
43
36
|
if ('exists' in expression) {
|
|
44
|
-
if (expression.exists.nodes.length > MAX_VARIABLES) {
|
|
45
|
-
fail(`${path}/exists/nodes`, 'Policy exists exceeds the V1 variable budget.');
|
|
46
|
-
}
|
|
47
37
|
const nested = new Set(scope);
|
|
48
38
|
for (const [index, node] of expression.exists.nodes.entries()) {
|
|
49
39
|
const id = node.variable.id;
|
|
@@ -59,8 +49,6 @@ function validatePattern(context, expression, path, scope, declared) {
|
|
|
59
49
|
return;
|
|
60
50
|
}
|
|
61
51
|
const values = 'allOf' in expression ? expression.allOf : expression.anyOf;
|
|
62
|
-
if (values.length === 0)
|
|
63
|
-
fail(path, 'Policy pattern composition must be non-empty.');
|
|
64
52
|
values.forEach((value, index) => validatePattern(context, value, `${path}/${index}`, scope, declared));
|
|
65
53
|
}
|
|
66
54
|
function validatePolicyTerm(context, term, path, scope) {
|
|
@@ -1,28 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type PatternBranch } from '../../../../language/policy/analysis/branches.js';
|
|
1
|
+
import { PolicyTyping } from '../../../../language/policy/analysis/typing.js';
|
|
3
2
|
import { type PolicyExpression } from '../../../../language/policy/model/policy.js';
|
|
4
3
|
import { type CompiledSchemaEntry } from '../../../model/schema.js';
|
|
5
4
|
import { type SemanticIndex } from '../context.js';
|
|
6
|
-
import { type CompiledObjectContract, type CompiledPolicyUse } from './contracts.js';
|
|
7
5
|
/** Types one entry's Policies against the Node Classes of its own closure, as source admission. */
|
|
8
|
-
export declare
|
|
9
|
-
readonly context: SemanticIndex;
|
|
10
|
-
readonly entry: CompiledSchemaEntry;
|
|
11
|
-
readonly normalized: ReadonlyMap<string, PolicyExpression>;
|
|
12
|
-
readonly allNodeClasses: readonly ClassRef[];
|
|
13
|
-
readonly concreteNodeClasses: readonly ClassRef[];
|
|
14
|
-
constructor(context: SemanticIndex, entry: CompiledSchemaEntry, normalized: ReadonlyMap<string, PolicyExpression>, origins: ReadonlySet<string>);
|
|
15
|
-
expandedBranches(name: string, visiting: Set<string>, namespace: string): readonly PatternBranch[] | undefined;
|
|
16
|
-
policyAccepts(name: string, object: CompiledObjectContract): boolean;
|
|
17
|
-
policyBranchTyping(name: string, object: CompiledObjectContract): readonly boolean[] | undefined;
|
|
18
|
-
policyAcceptsEdge(name: string, source: CompiledObjectContract, target: CompiledObjectContract): boolean;
|
|
19
|
-
concreteEndpointClasses(accepts: readonly ClassRef[]): readonly ClassRef[];
|
|
20
|
-
endpointsOverlap(left: readonly ClassRef[], right: readonly ClassRef[]): boolean;
|
|
21
|
-
branchIsTyped(branch: PatternBranch, use: CompiledPolicyUse): boolean;
|
|
22
|
-
private constraintsSatisfiable;
|
|
23
|
-
private applyInitial;
|
|
24
|
-
private applyExact;
|
|
25
|
-
private applyAnyNodeClass;
|
|
26
|
-
private applyRequirement;
|
|
27
|
-
private applyEndpoint;
|
|
28
|
-
}
|
|
6
|
+
export declare function compiledPolicyTyping(context: SemanticIndex, entry: CompiledSchemaEntry, normalized: ReadonlyMap<string, PolicyExpression>, origins: ReadonlySet<string>): PolicyTyping;
|