@astrale-os/kernel-dsl 0.2.0-beta.30 → 0.2.0-beta.31
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/builder/callable/authoring.d.ts +1 -1
- package/dist/v1/builder/lowering/schema/capture.js +7 -2
- package/dist/v1/builder/lowering/schema/context.d.ts +2 -2
- package/dist/v1/builder/lowering/schema/context.js +17 -7
- package/dist/v1/builder/lowering/schema/ownership.d.ts +1 -1
- package/dist/v1/builder/lowering/schema/ownership.js +2 -1
- package/dist/v1/compiled/admission/accept.js +13 -2
- package/dist/v1/compiled/admission/semantics.js +19 -9
- package/dist/v1/language/index.d.ts +1 -1
- package/dist/v1/language/index.js +1 -1
- package/dist/v1/language/policy/analysis/branches.js +2 -2
- package/dist/v1/language/policy/index.d.ts +1 -1
- package/dist/v1/language/policy/index.js +1 -1
- package/dist/v1/language/policy/model/policy.d.ts +5 -2
- package/dist/v1/language/policy/model/policy.js +9 -0
- package/dist/v1/language/policy/normalization/normalize.js +2 -2
- package/dist/v1/schema/resolution/origins.js +6 -4
- package/dist/v1/schema/validation/domain.structure.js +1 -0
- package/dist/v1/schema/validation/policy/budgets.js +3 -3
- package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
- package/dist/v1/schema/validation/policy/objects.js +12 -6
- package/package.json +1 -1
|
@@ -91,7 +91,7 @@ export interface Method<out Projection = unknown> {
|
|
|
91
91
|
export type ProjectionOfCallable<Value extends Function | Method> = Value extends Function<infer Projection> ? Projection : Value extends Method<infer Projection> ? Projection : never;
|
|
92
92
|
/** Internal lowering access; Callable authoring handles expose no public configuration object. */
|
|
93
93
|
export declare function callableConfiguration(value: Function | Method): CallableInput;
|
|
94
|
-
export type PolicyObjectAuthoring = Class | Function | Policy | View | CoreNode;
|
|
94
|
+
export type PolicyObjectAuthoring = Class | Function | Method | Policy | View | CoreNode;
|
|
95
95
|
export type PolicyObjectInput = Lazy<PolicyObjectAuthoring | PolicyObjectRef>;
|
|
96
96
|
export declare function func<const Config extends FunctionInput, Input = ValueInputOf<Config['input']>, Output = CallableOutputOf<Config['output']>, Auth extends FunctionAuth = Config['auth']>(config: Config): Function<CallableProjection<Input, Output, Auth, false, 'default'>>;
|
|
97
97
|
export declare function method<const Config extends MethodInput, Input = ValueInputOf<Config['input']>, Output = CallableOutputOf<Config['output']>, Auth extends FunctionAuth = Config['auth'], Static extends boolean = Config extends {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { MethodKey } from '../../../addressing/index.js';
|
|
2
1
|
import { classConfiguration } from '../../class/authoring.js';
|
|
3
2
|
import { escapeToken, fail } from '../../schema/diagnostic.js';
|
|
4
3
|
import { isAuthoringValue } from '../../schema/handle.js';
|
|
@@ -42,7 +41,13 @@ function captureExecutables(input, context) {
|
|
|
42
41
|
for (const [methodName, method] of Object.entries(methods ?? {})) {
|
|
43
42
|
const pointer = `/classes/${escapeToken(definitionName)}/methods/${escapeToken(methodName)}`;
|
|
44
43
|
assertMethod(method, pointer);
|
|
45
|
-
|
|
44
|
+
const ref = {
|
|
45
|
+
kind: 'method',
|
|
46
|
+
owner: { origin: context.origin, kind: 'class', name: definitionName },
|
|
47
|
+
name: methodName,
|
|
48
|
+
};
|
|
49
|
+
context.ownership.captureDefinition(method, ref, pointer);
|
|
50
|
+
context.capturePolicyObject(method, ref);
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
53
|
for (const [name, value] of Object.entries(input.views ?? {})) {
|
|
@@ -2,7 +2,7 @@ import type { CoreRef, ClassRef, DefinitionRef, FunctionRef, PolicyRef, ViewRef
|
|
|
2
2
|
import type { DomainDependency } from '../../../addressing/index.js';
|
|
3
3
|
import type { ClassKind } from '../../../language/class/model/class.js';
|
|
4
4
|
import type { CoreEndpointRef } from '../../../language/core/model/core.js';
|
|
5
|
-
import type { PolicyObjectRef } from '../../../language/
|
|
5
|
+
import type { PolicyObjectRef } from '../../../language/index.js';
|
|
6
6
|
import type { ValueSchemaRegistry } from '../../../language/value/reference/registry.js';
|
|
7
7
|
import type { DomainSchema, DomainSchemaIR } from '../../../schema/model/schema.js';
|
|
8
8
|
import type { Function, PolicyObjectInput } from '../../callable/authoring.js';
|
|
@@ -40,5 +40,5 @@ export declare class BuilderContext {
|
|
|
40
40
|
noteDomainEndpointReferences(schema: DomainSchemaIR): void;
|
|
41
41
|
private assertVisible;
|
|
42
42
|
private classKind;
|
|
43
|
-
|
|
43
|
+
capturePolicyObject(value: object, ref: PolicyObjectRef): void;
|
|
44
44
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { compareDefinitionRefs, compareUnicode, definitionRefIndex, } from '../../../addressing/ordering.js';
|
|
2
2
|
import { DEPENDENCY_ALIAS_PATTERN } from '../../../addressing/patterns.js';
|
|
3
|
+
import { policyObjectKey, policyObjectOrigin } from '../../../language/index.js';
|
|
3
4
|
import { graphNodePathSchema } from '../../../language/value/syntax/node-path/schema.js';
|
|
4
5
|
import { revisionOfDomainSchema } from '../../../schema/canonical/revision.js';
|
|
5
6
|
import { requireDomainClosure } from '../../../schema/resolution/closure.js';
|
|
@@ -114,16 +115,18 @@ export class BuilderContext {
|
|
|
114
115
|
: typeof value === 'object' && value !== null
|
|
115
116
|
? (this.policyObjects.get(value) ?? this.ownership.definition(value))
|
|
116
117
|
: undefined;
|
|
117
|
-
const
|
|
118
|
+
const origin = ref === undefined ? undefined : policyObjectOrigin(ref);
|
|
119
|
+
const dependency = origin === undefined ? undefined : this.#dependencies.get(origin)?.schema;
|
|
118
120
|
const admitted = ref !== undefined &&
|
|
119
|
-
(
|
|
120
|
-
? this.policyObjectRefs.has(
|
|
121
|
+
(origin === this.origin
|
|
122
|
+
? this.policyObjectRefs.has(policyObjectKey(ref))
|
|
121
123
|
: dependency !== undefined && hasPolicyObject(dependency, ref));
|
|
122
124
|
if (!admitted || ref === undefined) {
|
|
123
|
-
fail('BUILDER_POLICY_REF', pointer, 'Policy ref(...) must name one registered local or direct-dependency Definition, Function, Policy, View, or Core Node.');
|
|
125
|
+
fail('BUILDER_POLICY_REF', pointer, 'Policy ref(...) must name one registered local or direct-dependency Definition, Function, Method, Policy, View, or Core Node.');
|
|
124
126
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
const admittedOrigin = policyObjectOrigin(ref);
|
|
128
|
+
if (admittedOrigin !== this.origin)
|
|
129
|
+
this.usedForeignOrigins.add(admittedOrigin);
|
|
127
130
|
return { ...ref };
|
|
128
131
|
}
|
|
129
132
|
resolveCoreEndpoint(value, pointer) {
|
|
@@ -196,7 +199,7 @@ export class BuilderContext {
|
|
|
196
199
|
}
|
|
197
200
|
capturePolicyObject(value, ref) {
|
|
198
201
|
this.policyObjects.set(value, ref);
|
|
199
|
-
this.policyObjectRefs.add(
|
|
202
|
+
this.policyObjectRefs.add(policyObjectKey(ref));
|
|
200
203
|
}
|
|
201
204
|
}
|
|
202
205
|
function escapePointer(value) {
|
|
@@ -234,6 +237,8 @@ function isPolicyObjectRef(value) {
|
|
|
234
237
|
if (typeof value !== 'object' || value === null)
|
|
235
238
|
return false;
|
|
236
239
|
const candidate = value;
|
|
240
|
+
if (candidate.kind === 'method')
|
|
241
|
+
return isDefinitionRef(candidate.owner) && typeof candidate.name === 'string';
|
|
237
242
|
return (typeof candidate.origin === 'string' &&
|
|
238
243
|
typeof candidate.name === 'string' &&
|
|
239
244
|
(candidate.kind === 'class' ||
|
|
@@ -252,6 +257,11 @@ function definitionRefsOf(schema) {
|
|
|
252
257
|
}
|
|
253
258
|
function hasPolicyObject(schema, ref) {
|
|
254
259
|
switch (ref.kind) {
|
|
260
|
+
case 'method': {
|
|
261
|
+
const owner = schema.classes[ref.owner.name];
|
|
262
|
+
const method = owner?.kind === 'node' ? owner.methods[ref.name] : undefined;
|
|
263
|
+
return method !== undefined && method.inheritance !== 'abstract';
|
|
264
|
+
}
|
|
255
265
|
case 'class':
|
|
256
266
|
return Object.hasOwn(schema.classes, ref.name);
|
|
257
267
|
case 'function':
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PolicyObjectRef } from '../../../language/
|
|
1
|
+
import type { PolicyObjectRef } from '../../../language/index.js';
|
|
2
2
|
export declare class OwnershipCapture {
|
|
3
3
|
#private;
|
|
4
4
|
captureDefinition(value: object, ref: PolicyObjectRef, pointer: string): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { policyObjectKey } from '../../../language/index.js';
|
|
1
2
|
import { fail } from '../../schema/diagnostic.js';
|
|
2
3
|
const definitionOwners = new WeakMap();
|
|
3
4
|
const semanticOwners = new WeakMap();
|
|
@@ -5,7 +6,7 @@ export class OwnershipCapture {
|
|
|
5
6
|
#definitions = new Map();
|
|
6
7
|
#owners = new Map();
|
|
7
8
|
captureDefinition(value, ref, pointer) {
|
|
8
|
-
this.capture(value,
|
|
9
|
+
this.capture(value, policyObjectKey(ref), pointer);
|
|
9
10
|
this.#definitions.set(value, ref);
|
|
10
11
|
}
|
|
11
12
|
capture(value, owner, pointer) {
|
|
@@ -494,7 +494,7 @@ function policyTerm(input, variableOnly, path) {
|
|
|
494
494
|
const value = object(input, 'Policy pattern term', path);
|
|
495
495
|
if (!variableOnly && value.kind === 'ref') {
|
|
496
496
|
exact(value, ['kind', 'ref'], 'Policy reference term', path);
|
|
497
|
-
|
|
497
|
+
policyObjectRef(value.ref, `${path}/ref`);
|
|
498
498
|
return;
|
|
499
499
|
}
|
|
500
500
|
if (value.kind === 'variable') {
|
|
@@ -548,7 +548,7 @@ function policyCheckObject(input, objectPath) {
|
|
|
548
548
|
}
|
|
549
549
|
else if (target.kind === 'ref') {
|
|
550
550
|
exact(target, ['kind', 'ref'], 'Callable Policy object ref', objectPath);
|
|
551
|
-
|
|
551
|
+
policyObjectRef(target.ref, `${objectPath}/ref`);
|
|
552
552
|
}
|
|
553
553
|
else
|
|
554
554
|
invalid('Callable Policy object', undefined, `${objectPath}/kind`);
|
|
@@ -560,6 +560,17 @@ function coreEndpoint(input, label, path) {
|
|
|
560
560
|
else
|
|
561
561
|
definitionRef(value, 'core', label, path);
|
|
562
562
|
}
|
|
563
|
+
function policyObjectRef(input, path) {
|
|
564
|
+
const ref = object(input, 'Policy object ref', path);
|
|
565
|
+
if (ref.kind !== 'method') {
|
|
566
|
+
definitionRef(input, undefined, 'Policy object ref', path);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
exact(ref, ['kind', 'owner', 'name'], 'Policy Method ref', path);
|
|
570
|
+
definitionRef(ref.owner, 'class', 'Policy Method owner', `${path}/owner`);
|
|
571
|
+
if (typeof ref.name !== 'string' || !MEMBER_NAME_PATTERN.test(ref.name))
|
|
572
|
+
invalid('Policy Method name', undefined, `${path}/name`);
|
|
573
|
+
}
|
|
563
574
|
function definitionRef(input, kind, label, path) {
|
|
564
575
|
if (!isDefinitionRef(input) || (kind !== undefined && input.kind !== kind))
|
|
565
576
|
invalid(label, undefined, path);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { json } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { Key, PropertyKey as PropertyKeyValue } from '../../addressing/index.js';
|
|
3
3
|
import { compareUnicode } from '../../addressing/ordering.js';
|
|
4
|
+
import { policyObjectOrigin, policyVariableClass } from '../../language/index.js';
|
|
4
5
|
import { branchesOf, branchProduct, capBranches, isConnected, targetMode, termKey, } from '../../language/policy/analysis/branches.js';
|
|
5
6
|
import { BRANCH_OVERFLOW, MAX_BRANCHES, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, MAX_DOMAINS, MAX_EDGES, MAX_PATTERN_DEPTH, MAX_REPEAT, MAX_VARIABLES, measureChecks, } from '../../language/policy/analysis/budgets.js';
|
|
6
|
-
import { policyVariableClass } from '../../language/policy/model/policy.js';
|
|
7
7
|
import { normalizePolicyChecks, normalizePolicyExpression, } from '../../language/policy/normalization/normalize.js';
|
|
8
8
|
import { validateValueProgram } from '../../language/value/evaluate/program.js';
|
|
9
9
|
import { GRAPH_NODE_PATH_SCHEMA_ID } from '../../language/value/syntax/node-path/schema.js';
|
|
@@ -348,15 +348,15 @@ function validatePolicyExpression(context, entry, expression, path, local) {
|
|
|
348
348
|
}
|
|
349
349
|
function validatePattern(context, expression, path, scope, declared) {
|
|
350
350
|
if ('sameNode' in expression) {
|
|
351
|
-
validatePolicyTerm(expression.sameNode.left, `${path}/sameNode/left`, scope);
|
|
352
|
-
validatePolicyTerm(expression.sameNode.right, `${path}/sameNode/right`, scope);
|
|
351
|
+
validatePolicyTerm(context, expression.sameNode.left, `${path}/sameNode/left`, scope);
|
|
352
|
+
validatePolicyTerm(context, expression.sameNode.right, `${path}/sameNode/right`, scope);
|
|
353
353
|
return;
|
|
354
354
|
}
|
|
355
355
|
if ('source' in expression) {
|
|
356
356
|
if (context.classes.get(Key.of(expression.class))?.value.kind !== 'edge')
|
|
357
357
|
fail(`${path}/class`, 'Policy pattern Class must resolve to an Edge Class.');
|
|
358
|
-
validatePolicyTerm(expression.source, `${path}/source`, scope);
|
|
359
|
-
validatePolicyTerm(expression.target, `${path}/target`, scope);
|
|
358
|
+
validatePolicyTerm(context, expression.source, `${path}/source`, scope);
|
|
359
|
+
validatePolicyTerm(context, expression.target, `${path}/target`, scope);
|
|
360
360
|
if (expression.repeat !== undefined &&
|
|
361
361
|
(!Number.isInteger(expression.repeat.min) ||
|
|
362
362
|
!Number.isInteger(expression.repeat.max) ||
|
|
@@ -389,10 +389,18 @@ function validatePattern(context, expression, path, scope, declared) {
|
|
|
389
389
|
fail(path, 'Policy pattern composition must be non-empty.');
|
|
390
390
|
values.forEach((value, index) => validatePattern(context, value, `${path}/${index}`, scope, declared));
|
|
391
391
|
}
|
|
392
|
-
function validatePolicyTerm(term, path, scope) {
|
|
392
|
+
function validatePolicyTerm(context, term, path, scope) {
|
|
393
|
+
if (term.kind === 'ref' && term.ref.kind === 'method')
|
|
394
|
+
validatePolicyMethod(context, term.ref, `${path}/ref`);
|
|
393
395
|
if (term.kind === 'variable' && !scope.has(term.id))
|
|
394
396
|
fail(path, 'Policy variable is outside its declaring scope.');
|
|
395
397
|
}
|
|
398
|
+
function validatePolicyMethod(context, ref, path) {
|
|
399
|
+
const owner = context.classes.get(Key.of(ref.owner))?.value;
|
|
400
|
+
const method = owner?.kind === 'node' ? owner.methods.find((method) => method.name === ref.name) : undefined;
|
|
401
|
+
if (method === undefined || method.inheritance === 'abstract')
|
|
402
|
+
fail(path, 'Policy Method ref must name an exact concrete Method declaration.');
|
|
403
|
+
}
|
|
396
404
|
function validatePolicyCycles(entry, local, entryIndex) {
|
|
397
405
|
const visiting = new Set();
|
|
398
406
|
const visited = new Set();
|
|
@@ -422,6 +430,8 @@ function validateCallablePolicy(context, entry, expression, inputIndex, fields,
|
|
|
422
430
|
fail(`${path}/check`, 'Callable Policy must reference a local named Policy.');
|
|
423
431
|
const objects = 'check' in expression ? { object: expression.object } : expression.sameNode;
|
|
424
432
|
for (const [side, object] of Object.entries(objects)) {
|
|
433
|
+
if (object.kind === 'ref' && object.ref.kind === 'method')
|
|
434
|
+
validatePolicyMethod(context, object.ref, `${path}/${side}/ref`);
|
|
425
435
|
if (object.kind === 'self' && !instanceMethod)
|
|
426
436
|
fail(`${path}/${side}`, 'self is valid only for an instance Method.');
|
|
427
437
|
if (object.kind === 'input' &&
|
|
@@ -590,7 +600,7 @@ function callableObjectContracts(context, entry, input, receiver, object) {
|
|
|
590
600
|
}
|
|
591
601
|
const projection = ref.kind === 'class'
|
|
592
602
|
? 'Class'
|
|
593
|
-
: ref.kind === 'function'
|
|
603
|
+
: ref.kind === 'function' || ref.kind === 'method'
|
|
594
604
|
? 'Function'
|
|
595
605
|
: ref.kind === 'policy'
|
|
596
606
|
? 'Policy'
|
|
@@ -893,7 +903,7 @@ function measureCompiledPattern(pattern, origin) {
|
|
|
893
903
|
edgeCounts: [1],
|
|
894
904
|
domains: new Set([
|
|
895
905
|
origin,
|
|
896
|
-
...[pattern.sameNode.left, pattern.sameNode.right].flatMap((term) => term.kind === 'ref' ? [term.ref
|
|
906
|
+
...[pattern.sameNode.left, pattern.sameNode.right].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
897
907
|
]),
|
|
898
908
|
};
|
|
899
909
|
if ('source' in pattern)
|
|
@@ -903,7 +913,7 @@ function measureCompiledPattern(pattern, origin) {
|
|
|
903
913
|
domains: new Set([
|
|
904
914
|
origin,
|
|
905
915
|
pattern.class.origin,
|
|
906
|
-
...[pattern.source, pattern.target].flatMap((term) => term.kind === 'ref' ? [term.ref
|
|
916
|
+
...[pattern.source, pattern.target].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
907
917
|
]),
|
|
908
918
|
};
|
|
909
919
|
if ('exists' in pattern) {
|
|
@@ -20,7 +20,7 @@ export type { Definition } from './definition.js';
|
|
|
20
20
|
export type { ResolvedDefinition, ResolvedDefinitionOf } from './resolved.js';
|
|
21
21
|
export type { Diagnostic, DiagnosticCode } from './validation/diagnostic.js';
|
|
22
22
|
export type * from './policy/model/policy.js';
|
|
23
|
-
export { policyVariableClass, policyVariableSelector } from './policy/model/policy.js';
|
|
23
|
+
export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './policy/model/policy.js';
|
|
24
24
|
export type * from './policy/resolved.js';
|
|
25
25
|
export type * from './view/model/view.js';
|
|
26
26
|
export type * from './view/resolved.js';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { stateMachine } from './state/index.js';
|
|
2
2
|
export { PropertyValues } from './class/property-values.js';
|
|
3
|
-
export { policyVariableClass, policyVariableSelector } from './policy/model/policy.js';
|
|
3
|
+
export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './policy/model/policy.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { definitionRefIndex } from '../../../addressing/ordering.js';
|
|
2
|
-
import { policyVariableSelector } from '../model/policy.js';
|
|
2
|
+
import { policyObjectKey, policyVariableSelector } from '../model/policy.js';
|
|
3
3
|
import { BRANCH_OVERFLOW } from './budgets.js';
|
|
4
4
|
export function branchesOf(pattern, namespace) {
|
|
5
5
|
const variables = collectVariableClasses(pattern, namespace);
|
|
@@ -62,7 +62,7 @@ export function termKey(term, namespace) {
|
|
|
62
62
|
return term.kind === 'variable'
|
|
63
63
|
? variableKey(namespace, term.id)
|
|
64
64
|
: term.kind === 'ref'
|
|
65
|
-
? `ref:${definitionRefIndex(term.ref)}`
|
|
65
|
+
? `ref:${term.ref.kind === 'method' ? policyObjectKey(term.ref) : definitionRefIndex(term.ref)}`
|
|
66
66
|
: term.kind;
|
|
67
67
|
}
|
|
68
68
|
function branchesForNode(pattern, namespace, variables) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export type * from './model/policy.js';
|
|
2
|
-
export { policyVariableClass, policyVariableSelector } from './model/policy.js';
|
|
2
|
+
export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './model/policy.js';
|
|
3
3
|
export type * from './resolved.js';
|
|
4
4
|
export * from './normalization/normalize.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { policyVariableClass, policyVariableSelector } from './model/policy.js';
|
|
1
|
+
export { policyVariableClass, policyVariableSelector, policyObjectKey, policyObjectOrigin, } from './model/policy.js';
|
|
2
2
|
export * from './normalization/normalize.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CoreRef, ClassRef, FunctionRef, PolicyRef, ViewRef, DefinitionBase } from '../../../addressing/index.js';
|
|
1
|
+
import type { CoreRef, ClassRef, FunctionRef, PolicyRef, ViewRef, DefinitionBase, MethodAddress } from '../../../addressing/index.js';
|
|
2
2
|
export type PolicyPatternTerm = {
|
|
3
3
|
readonly kind: 'subject';
|
|
4
4
|
} | {
|
|
@@ -85,7 +85,10 @@ export interface PolicyDefinition extends DefinitionBase<PolicyRef> {
|
|
|
85
85
|
readonly description?: string;
|
|
86
86
|
}
|
|
87
87
|
/** Local Domain members whose installed projection resolves through one exact member Path. */
|
|
88
|
-
export type PolicyObjectRef = ClassRef | FunctionRef | PolicyRef | ViewRef | CoreRef;
|
|
88
|
+
export type PolicyObjectRef = ClassRef | FunctionRef | PolicyRef | ViewRef | CoreRef | MethodAddress;
|
|
89
|
+
/** Exact projected identity, including Class-owned Method declarations. */
|
|
90
|
+
export declare function policyObjectKey(ref: PolicyObjectRef): string;
|
|
91
|
+
export declare function policyObjectOrigin(ref: PolicyObjectRef): string;
|
|
89
92
|
export type PolicyCheckObject = {
|
|
90
93
|
readonly kind: 'self';
|
|
91
94
|
} | {
|
|
@@ -7,3 +7,12 @@ export function policyVariableClass(variable) {
|
|
|
7
7
|
const selector = policyVariableSelector(variable);
|
|
8
8
|
return selector.kind === 'any' ? undefined : selector.class;
|
|
9
9
|
}
|
|
10
|
+
/** Exact projected identity, including Class-owned Method declarations. */
|
|
11
|
+
export function policyObjectKey(ref) {
|
|
12
|
+
return ref.kind === 'method'
|
|
13
|
+
? `${ref.owner.origin}:class.${ref.owner.name}.method.${ref.name}`
|
|
14
|
+
: `${ref.origin}:${ref.kind}.${ref.name}`;
|
|
15
|
+
}
|
|
16
|
+
export function policyObjectOrigin(ref) {
|
|
17
|
+
return ref.kind === 'method' ? ref.owner.origin : ref.origin;
|
|
18
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { json } from '@astrale-os/kernel-dsl/value';
|
|
2
2
|
import { definitionRefIndex, compareDefinitionRefs } from '../../../addressing/ordering.js';
|
|
3
|
-
import { policyVariableSelector } from '../model/policy.js';
|
|
3
|
+
import { policyObjectKey, policyVariableSelector } from '../model/policy.js';
|
|
4
4
|
const textEncoder = new TextEncoder();
|
|
5
5
|
export function normalizePolicyExpression(value) {
|
|
6
6
|
if ('match' in value) {
|
|
@@ -146,7 +146,7 @@ function termColor(term, colors) {
|
|
|
146
146
|
if (term.kind === 'variable')
|
|
147
147
|
return `variable:${colors.get(term.id) ?? '?'}`;
|
|
148
148
|
if (term.kind === 'ref')
|
|
149
|
-
return `ref:${definitionRefIndex(term.ref)}`;
|
|
149
|
+
return `ref:${term.ref.kind === 'method' ? policyObjectKey(term.ref) : definitionRefIndex(term.ref)}`;
|
|
150
150
|
return term.kind;
|
|
151
151
|
}
|
|
152
152
|
function collectFirstUseKeys(value, colors, result, prefix = '$') {
|
|
@@ -82,13 +82,13 @@ function collectPolicyPatternRefs(expression, add) {
|
|
|
82
82
|
if ('sameNode' in expression) {
|
|
83
83
|
for (const term of [expression.sameNode.left, expression.sameNode.right])
|
|
84
84
|
if (term.kind === 'ref')
|
|
85
|
-
add(term.ref);
|
|
85
|
+
add(term.ref.kind === 'method' ? term.ref.owner : term.ref);
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
if ('source' in expression) {
|
|
89
89
|
for (const term of [expression.source, expression.target])
|
|
90
90
|
if (term.kind === 'ref')
|
|
91
|
-
add(term.ref);
|
|
91
|
+
add(term.ref.kind === 'method' ? term.ref.owner : term.ref);
|
|
92
92
|
add(expression.class);
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
@@ -108,13 +108,15 @@ function collectPolicyCheckRefs(expression, add) {
|
|
|
108
108
|
if ('sameNode' in expression) {
|
|
109
109
|
for (const term of [expression.sameNode.left, expression.sameNode.right])
|
|
110
110
|
if (term.kind === 'ref')
|
|
111
|
-
add(term.ref);
|
|
111
|
+
add(term.ref.kind === 'method' ? term.ref.owner : term.ref);
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
if ('check' in expression) {
|
|
115
115
|
add(expression.check);
|
|
116
116
|
if (expression.object.kind === 'ref')
|
|
117
|
-
add(expression.object.ref
|
|
117
|
+
add(expression.object.ref.kind === 'method'
|
|
118
|
+
? expression.object.ref.owner
|
|
119
|
+
: expression.object.ref);
|
|
118
120
|
return;
|
|
119
121
|
}
|
|
120
122
|
const children = 'allOf' in expression ? expression.allOf : expression.anyOf;
|
|
@@ -63,6 +63,7 @@ const coreRefSchema = strictObject({
|
|
|
63
63
|
const domainRefSchema = strictObject({ kind: literal('domain') });
|
|
64
64
|
const coreEndpointRefSchema = discriminatedUnion('kind', [coreRefSchema, domainRefSchema]);
|
|
65
65
|
const policyObjectRefSchema = discriminatedUnion('kind', [
|
|
66
|
+
strictObject({ kind: literal('method'), owner: classRefSchema, name: memberNameSchema }),
|
|
66
67
|
classRefSchema,
|
|
67
68
|
functionRefSchema,
|
|
68
69
|
policyRefSchema,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { policyObjectOrigin, policyVariableClass } from '../../../language/index.js';
|
|
1
2
|
import { BRANCH_OVERFLOW, MAX_BRANCHES, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, MAX_DOMAINS, MAX_EDGES, MAX_PATTERN_DEPTH, MAX_REPEAT, MAX_VARIABLES, measureChecks, } from '../../../language/policy/analysis/budgets.js';
|
|
2
|
-
import { policyVariableClass } from '../../../language/policy/model/policy.js';
|
|
3
3
|
import { escapePointer } from './context.js';
|
|
4
4
|
export { BRANCH_OVERFLOW, MAX_BRANCHES, MAX_CHECK_DEPTH, MAX_CHECK_LEAVES, MAX_DOMAINS, MAX_EDGES, MAX_PATTERN_DEPTH, MAX_REPEAT, MAX_VARIABLES, measureChecks, };
|
|
5
5
|
export function validatePolicyBudgets(context) {
|
|
@@ -52,7 +52,7 @@ function measurePattern(pattern, ownOrigin) {
|
|
|
52
52
|
edgeCounts: [1],
|
|
53
53
|
domains: new Set([
|
|
54
54
|
ownOrigin,
|
|
55
|
-
...[pattern.sameNode.left, pattern.sameNode.right].flatMap((term) => term.kind === 'ref' ? [term.ref
|
|
55
|
+
...[pattern.sameNode.left, pattern.sameNode.right].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
56
56
|
]),
|
|
57
57
|
};
|
|
58
58
|
if (isEdge(pattern)) {
|
|
@@ -62,7 +62,7 @@ function measurePattern(pattern, ownOrigin) {
|
|
|
62
62
|
domains: new Set([
|
|
63
63
|
ownOrigin,
|
|
64
64
|
pattern.class.origin,
|
|
65
|
-
...[pattern.source, pattern.target].flatMap((term) => term.kind === 'ref' ? [term.ref
|
|
65
|
+
...[pattern.source, pattern.target].flatMap((term) => term.kind === 'ref' ? [policyObjectOrigin(term.ref)] : []),
|
|
66
66
|
]),
|
|
67
67
|
};
|
|
68
68
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PolicyObjectRef } from '../../../language/
|
|
1
|
+
import type { PolicyObjectRef } from '../../../language/index.js';
|
|
2
2
|
import type { PolicyValidationContext } from './context.js';
|
|
3
3
|
import type { ObjectContract } from './typing.js';
|
|
4
4
|
export declare function referenceContracts(validation: PolicyValidationContext, ref: PolicyObjectRef, pointer: string): readonly ObjectContract[] | undefined;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Key } from '../../../addressing/index.js';
|
|
2
1
|
import { definitionRefIndex } from '../../../addressing/ordering.js';
|
|
3
|
-
|
|
2
|
+
import { policyObjectKey, policyObjectOrigin } from '../../../language/index.js';
|
|
4
3
|
const KERNEL_ORIGIN = 'kernel.astrale.ai';
|
|
5
4
|
const PROJECTION_CLASS = nodeClassRef('Class');
|
|
6
5
|
const PROJECTION_FUNCTION = nodeClassRef('Function');
|
|
@@ -8,12 +7,12 @@ const PROJECTION_POLICY = nodeClassRef('Policy');
|
|
|
8
7
|
const PROJECTION_VIEW = nodeClassRef('View');
|
|
9
8
|
export function referenceContracts(validation, ref, pointer) {
|
|
10
9
|
const candidate = validation.environment.candidate;
|
|
11
|
-
const local = ref
|
|
12
|
-
const direct = Object.values(candidate.dependencies).some((entry) => entry.origin === ref
|
|
10
|
+
const local = policyObjectOrigin(ref) === candidate.origin;
|
|
11
|
+
const direct = Object.values(candidate.dependencies).some((entry) => entry.origin === policyObjectOrigin(ref));
|
|
13
12
|
const owner = local
|
|
14
13
|
? candidate
|
|
15
14
|
: direct
|
|
16
|
-
? validation.environment.dependencies.get(ref
|
|
15
|
+
? validation.environment.dependencies.get(policyObjectOrigin(ref))
|
|
17
16
|
: undefined;
|
|
18
17
|
if (owner === undefined)
|
|
19
18
|
return invalidPolicyObjectRef(validation, ref, pointer);
|
|
@@ -24,6 +23,13 @@ export function referenceContracts(validation, ref, pointer) {
|
|
|
24
23
|
? [{ kind: 'exact', ref: PROJECTION_CLASS }]
|
|
25
24
|
: invalidPolicyObjectRef(validation, ref, pointer);
|
|
26
25
|
}
|
|
26
|
+
case 'method': {
|
|
27
|
+
const declaringClass = owner.classes[ref.owner.name];
|
|
28
|
+
const method = declaringClass?.kind === 'node' ? declaringClass.methods[ref.name] : undefined;
|
|
29
|
+
return method === undefined || method.inheritance === 'abstract'
|
|
30
|
+
? invalidPolicyObjectRef(validation, ref, pointer)
|
|
31
|
+
: [{ kind: 'exact', ref: PROJECTION_FUNCTION }];
|
|
32
|
+
}
|
|
27
33
|
case 'function':
|
|
28
34
|
return owner.functions[ref.name] === undefined
|
|
29
35
|
? invalidPolicyObjectRef(validation, ref, pointer)
|
|
@@ -56,7 +62,7 @@ export function referenceContracts(validation, ref, pointer) {
|
|
|
56
62
|
return invalidPolicyObjectRef(validation, ref, pointer);
|
|
57
63
|
}
|
|
58
64
|
function invalidPolicyObjectRef(validation, ref, pointer) {
|
|
59
|
-
validation.add('PL_REF', `${pointer}/ref`, `${
|
|
65
|
+
validation.add('PL_REF', `${pointer}/ref`, `${policyObjectKey(ref)} is not an exact local or direct-dependency projected Policy object.`, policyObjectKey(ref));
|
|
60
66
|
return undefined;
|
|
61
67
|
}
|
|
62
68
|
function nodeClassRef(name) {
|