@astrale-os/sdk 0.5.0-beta.97 → 0.5.0-beta.98

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.0-beta.98](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.97...sdk-v0.5.0-beta.98) (2026-09-01)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * unify Domain functions layer
9
+
10
+ ### Features
11
+
12
+ * unify Domain functions layer ([326a3ea](https://github.com/astrale-os/sdk/commit/326a3ea7f296157d511a552cc159b82a34937f3a))
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * admit leading-digit domain slugs ([ec9288c](https://github.com/astrale-os/sdk/commit/ec9288cb8a2d0506dd91fcd4c01f47688086bbd1))
18
+
3
19
  ## [0.5.0-beta.97](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.96...sdk-v0.5.0-beta.97) (2026-08-31)
4
20
 
5
21
 
package/README.md CHANGED
@@ -72,14 +72,14 @@ guidance and the generated linter policy.
72
72
 
73
73
  ### Domain lint configuration
74
74
 
75
- `astrale-domain lint` defaults to the canonical layer roots and aliases, including `actions/`,
76
- `#actions`, and `#actions/*`. A Domain that uses different physical vocabulary can remap a
75
+ `astrale-domain lint` defaults to the canonical layer roots and aliases, including `functions/`,
76
+ `#functions`, and `#functions/*`. A Domain that uses different physical vocabulary can remap a
77
77
  semantic layer in `astrale.lint.json` without changing the rules attached to that layer:
78
78
 
79
79
  ```json
80
80
  {
81
81
  "layers": {
82
- "actions": {
82
+ "functions": {
83
83
  "sourcePath": "operations/",
84
84
  "alias": "#operations"
85
85
  }
@@ -11,18 +11,17 @@ type Same<Left, Right> = [Left] extends [Right] ? ([Right] extends [Left] ? true
11
11
  type ActionSchema<Value> = Value extends ActionDefinition<infer Schema, infer _Address, infer _Services> ? Schema : never;
12
12
  type WorkflowSchema<Value> = Value extends WorkflowDefinition<infer Schema, infer _Address, infer _Services> ? Schema : never;
13
13
  type RecipeIntegrations<Value> = Value extends ActionDefinition<infer _Schema, infer _Address, infer Definitions> ? Definitions : Value extends WorkflowDefinition<infer _Schema, infer _Address, infer Definitions> ? Definitions : never;
14
- type AdmitsRecipeSchema<Schema extends schema.DomainSchema, Actions extends readonly unknown[], Workflows extends readonly unknown[]> = [Actions[number] | Workflows[number]] extends [never] ? unknown : Same<ActionSchema<Actions[number]> | WorkflowSchema<Workflows[number]>, Schema> extends true ? unknown : never;
14
+ type AdmitsRecipeSchema<Schema extends schema.DomainSchema, Functions extends readonly unknown[]> = [Functions[number]] extends [never] ? unknown : Same<ActionSchema<Functions[number]> | WorkflowSchema<Functions[number]>, Schema> extends true ? unknown : never;
15
15
  type InitializationOf<Initialize extends RuntimeInitializerValue> = Awaited<ReturnType<Initialize>>;
16
16
  type AdmitsRecipeIntegrations<Definitions extends RuntimeIntegrations, Recipe> = RecipeIntegrations<Recipe> extends infer Required extends RuntimeIntegrations ? Exclude<keyof Required, keyof Definitions> extends never ? Required extends Pick<Definitions, Extract<keyof Required, keyof Definitions>> ? true : false : false : false;
17
- type AdmitsIntegrations<Definitions extends RuntimeIntegrations, Actions extends readonly unknown[], Workflows extends readonly unknown[]> = [Actions[number] | Workflows[number]] extends [never] ? unknown : false extends AdmitsRecipeIntegrations<Definitions, Actions[number] | Workflows[number]> ? never : unknown;
17
+ type AdmitsIntegrations<Definitions extends RuntimeIntegrations, Functions extends readonly unknown[]> = [Functions[number]] extends [never] ? unknown : false extends AdmitsRecipeIntegrations<Definitions, Functions[number]> ? never : unknown;
18
18
  type AdmitsProviders<Integrations extends RuntimeIntegrations, Initialize extends RuntimeInitializerValue> = Same<InitializationOf<Initialize>['providers'], Providers<Integrations>> extends true ? unknown : never;
19
- export interface RuntimeInput<Integrations extends RuntimeIntegrations, Initialize extends RuntimeInitializerValue, Actions extends readonly unknown[], Workflows extends readonly unknown[]> {
19
+ export interface RuntimeInput<Integrations extends RuntimeIntegrations, Initialize extends RuntimeInitializerValue, Functions extends readonly unknown[]> {
20
20
  readonly integrations: Integrations;
21
21
  readonly initialize: Initialize;
22
- readonly actions: Actions;
23
- readonly workflows: Workflows;
22
+ readonly functions: Functions;
24
23
  }
25
24
  /** Define one inert Runtime declaration; realization requires an exact loaded DSL Domain. */
26
- export declare function defineRuntime<Schema extends schema.DomainSchema>(): <const Integrations extends RuntimeIntegrations, Initialize extends AnyRuntimeInitializer<Schema>, const Actions extends readonly unknown[], const Workflows extends readonly unknown[]>(input: RuntimeInput<Integrations, Initialize, Actions, Workflows> & AdmitsRecipeSchema<Schema, Actions, Workflows> & AdmitsIntegrations<Integrations, Actions, Workflows> & AdmitsProviders<Integrations, Initialize>) => Runtime<Schema, Integrations, Initialize, Actions, Workflows>;
25
+ export declare function defineRuntime<Schema extends schema.DomainSchema>(): <const Integrations extends RuntimeIntegrations, Initialize extends AnyRuntimeInitializer<Schema>, const Functions extends readonly unknown[]>(input: RuntimeInput<Integrations, Initialize, Functions> & AdmitsRecipeSchema<Schema, Functions> & AdmitsIntegrations<Integrations, Functions> & AdmitsProviders<Integrations, Initialize>) => Runtime<Schema, Integrations, Initialize, Functions>;
27
26
  export declare function isRuntime(input: unknown): input is Runtime;
28
27
  export {};
@@ -8,11 +8,8 @@ export function defineRuntime() {
8
8
  if (input === null || typeof input !== 'object' || Array.isArray(input))
9
9
  invalid();
10
10
  const keys = Reflect.ownKeys(input);
11
- if (keys.length !== 4 ||
12
- !keys.every((key) => key === 'integrations' ||
13
- key === 'initialize' ||
14
- key === 'actions' ||
15
- key === 'workflows')) {
11
+ if (keys.length !== 3 ||
12
+ !keys.every((key) => key === 'integrations' || key === 'initialize' || key === 'functions')) {
16
13
  invalid();
17
14
  }
18
15
  if (input.integrations === null ||
@@ -23,19 +20,15 @@ export function defineRuntime() {
23
20
  if (typeof input.initialize !== 'function') {
24
21
  throw new TypeError('Runtime initialize must be a function.');
25
22
  }
26
- if (!Array.isArray(input.actions) || input.actions.some((action) => !isAction(action))) {
27
- throw new TypeError('Runtime actions must contain only admitted Actions.');
28
- }
29
- if (!Array.isArray(input.workflows) ||
30
- input.workflows.some((workflow) => !isWorkflow(workflow))) {
31
- throw new TypeError('Runtime workflows must contain only admitted Workflows.');
23
+ if (!Array.isArray(input.functions) ||
24
+ input.functions.some((implementation) => !isAction(implementation) && !isWorkflow(implementation))) {
25
+ throw new TypeError('Runtime functions must contain only admitted Actions and Workflows.');
32
26
  }
33
27
  const runtime = Object.freeze({
34
28
  kind: 'runtime',
35
29
  integrations: admitIntegrations(input.integrations),
36
30
  initialize: input.initialize,
37
- actions: Object.freeze([...input.actions]),
38
- workflows: Object.freeze([...input.workflows]),
31
+ functions: Object.freeze([...input.functions]),
39
32
  });
40
33
  admittedRuntimes.add(runtime);
41
34
  return runtime;
@@ -45,5 +38,5 @@ export function isRuntime(input) {
45
38
  return input !== null && typeof input === 'object' && admittedRuntimes.has(input);
46
39
  }
47
40
  function invalid() {
48
- throw new TypeError('Runtime definition must contain exactly integrations, initialize, actions, and workflows.');
41
+ throw new TypeError('Runtime definition must contain exactly integrations, initialize, and functions.');
49
42
  }
@@ -6,12 +6,11 @@ import type { RuntimeWorkflow } from './workflows.js';
6
6
  export type RuntimeImplementation = RuntimeAction | RuntimeWorkflow;
7
7
  declare const RUNTIME_SCHEMA: unique symbol;
8
8
  /** Inert authored Runtime declaration; exact Domain association occurs during realization. */
9
- export interface Runtime<Schema extends schema.DomainSchema = schema.DomainSchema, Integrations extends RuntimeIntegrations = RuntimeIntegrations, Initialize extends RuntimeInitializer<never, RuntimeInitialization, Schema> = RuntimeInitializer<never, RuntimeInitialization, Schema>, Actions extends readonly unknown[] = readonly unknown[], Workflows extends readonly unknown[] = readonly unknown[]> {
9
+ export interface Runtime<Schema extends schema.DomainSchema = schema.DomainSchema, Integrations extends RuntimeIntegrations = RuntimeIntegrations, Initialize extends RuntimeInitializer<never, RuntimeInitialization, Schema> = RuntimeInitializer<never, RuntimeInitialization, Schema>, Functions extends readonly unknown[] = readonly unknown[]> {
10
10
  readonly kind: 'runtime';
11
11
  readonly integrations: Integrations;
12
12
  readonly initialize: Initialize;
13
- readonly actions: Actions;
14
- readonly workflows: Workflows;
13
+ readonly functions: Functions;
15
14
  readonly [RUNTIME_SCHEMA]: Schema;
16
15
  }
17
16
  /** Recover the exact Schema witness retained by one authored Runtime. */
@@ -26,7 +25,6 @@ export interface RuntimeRegistry {
26
25
  }
27
26
  /** Prove unique and exhaustive Action/Workflow coverage of the root executable set. */
28
27
  export declare function admitRuntimeRegistry(domain: Domain, input: {
29
- readonly actions: unknown;
30
- readonly workflows: unknown;
28
+ readonly functions: unknown;
31
29
  }): RuntimeRegistry;
32
30
  export {};
@@ -1,11 +1,20 @@
1
+ import { isAction } from '../action/index.js';
2
+ import { isWorkflow } from '../workflow/index.js';
1
3
  import { admitActions } from './actions.js';
2
4
  import { runtimeCallables } from './callables.js';
3
5
  import { admitWorkflows } from './workflows.js';
4
6
  /** Prove unique and exhaustive Action/Workflow coverage of the root executable set. */
5
7
  export function admitRuntimeRegistry(domain, input) {
6
8
  const callables = runtimeCallables(domain);
7
- const actions = admitActions(callables, input.actions);
8
- const workflows = admitWorkflows(callables, input.workflows);
9
+ if (!Array.isArray(input.functions)) {
10
+ throw new TypeError('Runtime functions must be an array.');
11
+ }
12
+ const unknown = input.functions.filter((implementation) => !isAction(implementation) && !isWorkflow(implementation));
13
+ if (unknown.length > 0) {
14
+ throw new TypeError('Runtime functions must contain only admitted Actions and Workflows.');
15
+ }
16
+ const actions = admitActions(callables, input.functions.filter(isAction));
17
+ const workflows = admitWorkflows(callables, input.functions.filter(isWorkflow));
9
18
  const implementations = [...actions, ...workflows];
10
19
  const addresses = new Set();
11
20
  for (const implementation of implementations) {
@@ -3,8 +3,8 @@ import { importedSymbol, resolveProjectImport, unwrap, visit, } from '../../adap
3
3
  import { ambiguity, production, violation } from './shared.js';
4
4
  export const actionRules = [
5
5
  {
6
- id: 'ACT-ONE-IMPL',
7
- ruleRevision: '3c5e7f05c95826ea9ba14cdb6c1ed30dd190f3774bfbad3a2dfa607aada4a044',
6
+ id: 'FNC-ONE-IMPL',
7
+ ruleRevision: '98a614772dec03f5a5c669d0b0efcca8d811a2ed6de91347c38c6bd06fe2a84e',
8
8
  evaluate(project) {
9
9
  const evidence = [];
10
10
  const registered = new Map();
@@ -21,18 +21,18 @@ export const actionRules = [
21
21
  evidence.push(ambiguity(file, node, 'defineRuntime input is not a static object literal.'));
22
22
  return;
23
23
  }
24
- const actions = input.properties.find((property) => (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property)) &&
24
+ const functions = input.properties.find((property) => (ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property)) &&
25
25
  (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) &&
26
- property.name.text === 'actions');
27
- if (!actions)
26
+ property.name.text === 'functions');
27
+ if (!functions)
28
28
  return;
29
- const registry = ts.isPropertyAssignment(actions)
30
- ? unwrap(actions.initializer)
31
- : ts.isShorthandPropertyAssignment(actions)
32
- ? resolveLocalInitializer(file.source, actions.name.text)
29
+ const registry = ts.isPropertyAssignment(functions)
30
+ ? unwrap(functions.initializer)
31
+ : ts.isShorthandPropertyAssignment(functions)
32
+ ? resolveLocalInitializer(file.source, functions.name.text)
33
33
  : undefined;
34
34
  if (!registry) {
35
- evidence.push(ambiguity(file, actions, 'defineRuntime actions binding cannot be resolved locally.'));
35
+ evidence.push(ambiguity(file, functions, 'defineRuntime functions binding cannot be resolved locally.'));
36
36
  return;
37
37
  }
38
38
  const objectValues = inspectObjectValuesRegistry(project, file, registry);
@@ -45,29 +45,29 @@ export const actionRules = [
45
45
  return;
46
46
  }
47
47
  if (!ts.isArrayLiteralExpression(registry)) {
48
- evidence.push(ambiguity(file, registry, 'defineRuntime actions is not a static array literal.'));
48
+ evidence.push(ambiguity(file, registry, 'defineRuntime functions is not a static array literal.'));
49
49
  return;
50
50
  }
51
51
  visitActionLeaves(registry, (expression) => {
52
52
  const value = unwrap(expression);
53
53
  if (!ts.isIdentifier(value)) {
54
- evidence.push(violation(file, value, 'Action must be one imported Actions binding.'));
54
+ evidence.push(violation(file, value, 'Function must be one imported Functions binding.'));
55
55
  return;
56
56
  }
57
57
  const symbol = importedSymbol(file, value);
58
58
  const sourceImport = symbol && file.imports.find(({ specifier }) => specifier === symbol.module);
59
59
  const target = sourceImport && resolveProjectImport(project, file, sourceImport.specifier);
60
- if (target?.layer === 'actions' && !target.submodule) {
61
- evidence.push(ambiguity(file, value, `Action ${value.text} reaches the Actions layer facade but its ultimate semantic submodule owner is unresolved.`));
60
+ if (target?.layer === 'functions' && !target.submodule) {
61
+ evidence.push(ambiguity(file, value, `Function ${value.text} reaches the Functions layer facade but its ultimate semantic submodule owner is unresolved.`));
62
62
  return;
63
63
  }
64
- if (!target || target.layer !== 'actions' || !target.submodule) {
65
- evidence.push(violation(file, value, `Action ${value.text} is not owned by one Actions submodule.`));
64
+ if (!target || target.layer !== 'functions' || !target.submodule) {
65
+ evidence.push(violation(file, value, `Function ${value.text} is not owned by one Functions submodule.`));
66
66
  return;
67
67
  }
68
68
  const key = `${target.path}\0${symbol.name}`;
69
69
  if (registered.has(key)) {
70
- evidence.push(violation(file, value, `Action ${value.text} is registered more than once from ${target.path}.`));
70
+ evidence.push(violation(file, value, `Function ${value.text} is registered more than once from ${target.path}.`));
71
71
  }
72
72
  else {
73
73
  registered.set(key, value);
@@ -95,7 +95,7 @@ function inspectObjectValuesRegistry(project, file, expression) {
95
95
  if (!ts.isIdentifier(binding)) {
96
96
  return {
97
97
  kind: 'invalid',
98
- message: 'Object.values Actions registry must use one imported Actions facade.',
98
+ message: 'Object.values Functions registry must use one imported Functions facade.',
99
99
  ambiguous: false,
100
100
  };
101
101
  }
@@ -108,10 +108,10 @@ function inspectObjectValuesRegistry(project, file, expression) {
108
108
  (namespaceModule && ts.isStringLiteral(namespaceModule) ? namespaceModule.text : undefined);
109
109
  const sourceImport = module === undefined ? undefined : file.imports.find(({ specifier }) => specifier === module);
110
110
  const target = sourceImport && resolveProjectImport(project, file, sourceImport.specifier);
111
- if (target?.layer !== 'actions' || target.submodule) {
111
+ if (target?.layer !== 'functions' || target.submodule) {
112
112
  return {
113
113
  kind: 'invalid',
114
- message: 'Object.values Actions registry must resolve to the Actions layer facade.',
114
+ message: 'Object.values Functions registry must resolve to the Functions layer facade.',
115
115
  ambiguous: target === undefined,
116
116
  };
117
117
  }
@@ -124,7 +124,7 @@ function inspectObjectValuesRegistry(project, file, expression) {
124
124
  !ts.isNamedExports(statement.exportClause)) {
125
125
  return {
126
126
  kind: 'invalid',
127
- message: 'Actions facade must use explicit named re-exports from semantic submodules.',
127
+ message: 'Functions facade must use explicit named re-exports from semantic submodules.',
128
128
  ambiguous: false,
129
129
  };
130
130
  }
@@ -132,14 +132,14 @@ function inspectObjectValuesRegistry(project, file, expression) {
132
132
  if (owner === undefined) {
133
133
  return {
134
134
  kind: 'invalid',
135
- message: 'Actions facade re-export owner cannot be resolved.',
135
+ message: 'Functions facade re-export owner cannot be resolved.',
136
136
  ambiguous: true,
137
137
  };
138
138
  }
139
- if (owner.layer !== 'actions' || !owner.submodule) {
139
+ if (owner.layer !== 'functions' || !owner.submodule) {
140
140
  return {
141
141
  kind: 'invalid',
142
- message: 'Actions facade re-exports a value without one semantic Actions submodule owner.',
142
+ message: 'Functions facade re-exports a value without one semantic Functions submodule owner.',
143
143
  ambiguous: false,
144
144
  };
145
145
  }
@@ -151,7 +151,7 @@ function inspectObjectValuesRegistry(project, file, expression) {
151
151
  modifiers?.some(({ kind }) => kind === ts.SyntaxKind.ExportKeyword)) {
152
152
  return {
153
153
  kind: 'invalid',
154
- message: 'Actions facade exports a root-owned value without a semantic submodule owner.',
154
+ message: 'Functions facade exports a root-owned value without a semantic submodule owner.',
155
155
  ambiguous: false,
156
156
  };
157
157
  }
@@ -160,7 +160,7 @@ function inspectObjectValuesRegistry(project, file, expression) {
160
160
  ? { kind: 'valid' }
161
161
  : {
162
162
  kind: 'invalid',
163
- message: 'Actions facade exports no statically owned Action bindings.',
163
+ message: 'Functions facade exports no statically owned Function bindings.',
164
164
  ambiguous: false,
165
165
  };
166
166
  }
@@ -3,14 +3,13 @@ import { importedSymbol, propertyChain, resolveProjectImport, unwrap, visit, } f
3
3
  import { ambiguity, definitionOriginAmbiguity, definitionObjects, forbiddenIoImport, production, propertyExpression, violation, } from './shared.js';
4
4
  const FORBIDDEN_LAYERS = new Set([
5
5
  'integrations',
6
- 'actions',
6
+ 'functions',
7
7
  'providers',
8
8
  'mutations',
9
9
  'queries',
10
10
  'scripts',
11
11
  'ui',
12
12
  'views',
13
- 'workflows',
14
13
  ]);
15
14
  export const migrationRules = [
16
15
  {
@@ -2,7 +2,7 @@ import ts from 'typescript';
2
2
  import { importedSymbol, propertyChain, staticText, unwrap, visit, } from '../../adapters/typescript/index.js';
3
3
  import { ambiguity, callback, DSL_MODULES, definitionOriginAmbiguity, definitionObjects, domainProjectorEvidence, forbiddenIoImport, hasForbiddenGlobalCall, production, violation, } from './shared.js';
4
4
  import { stateMachineIdentity, statePropertyIdentity } from './state-machine.js';
5
- const FORBIDDEN_LAYERS = new Set(['integrations', 'actions', 'providers', 'queries', 'workflows']);
5
+ const FORBIDDEN_LAYERS = new Set(['integrations', 'functions', 'providers', 'queries']);
6
6
  const FORBIDDEN_CALLS = new Set(['invoke', 'query', 'retry', 'run', 'submit']);
7
7
  export const mutationRules = [
8
8
  {
@@ -2,7 +2,7 @@ import ts from 'typescript';
2
2
  import { objectProperty, propertyChain, resolveImportedSymbol, resolveProjectImport, unwrap, visit, } from '../../adapters/typescript/index.js';
3
3
  import { ambiguity, production, violation } from './shared.js';
4
4
  const LOCAL_DOMAIN_LAYERS = new Set([
5
- 'actions',
5
+ 'functions',
6
6
  'mutations',
7
7
  'queries',
8
8
  'rules',
@@ -10,7 +10,6 @@ const LOCAL_DOMAIN_LAYERS = new Set([
10
10
  'states',
11
11
  'ui',
12
12
  'views',
13
- 'workflows',
14
13
  ]);
15
14
  const GRAPH_OPERATIONS = new Set(['mutate', 'query', 'invoke', 'defineAction', 'defineWorkflow']);
16
15
  export const providerRules = [
@@ -3,12 +3,11 @@ import { resolveProjectImport, unwrap, visit } from '../../adapters/typescript/i
3
3
  import { ambiguity, hasForbiddenGlobalCall, isLocallyBoundIdentifier, production, violation, } from './shared.js';
4
4
  const FORBIDDEN_LAYERS = new Set([
5
5
  'integrations',
6
- 'actions',
6
+ 'functions',
7
7
  'providers',
8
8
  'mutations',
9
9
  'ui',
10
10
  'views',
11
- 'workflows',
12
11
  ]);
13
12
  export const pureRuleRules = [
14
13
  {
@@ -4,13 +4,12 @@ import { ambiguity, DSL_MODULES, forbiddenIoImport, production, violation } from
4
4
  import { stateMachineConstructorOrigin, stateMachineOrigin, statePropertyIdentity, statePropertyOrigin, stateSchemaIdentity, } from './state-machine.js';
5
5
  const FORBIDDEN_LAYERS = new Set([
6
6
  'integrations',
7
- 'actions',
7
+ 'functions',
8
8
  'providers',
9
9
  'mutations',
10
10
  'queries',
11
11
  'ui',
12
12
  'views',
13
- 'workflows',
14
13
  ]);
15
14
  const EXECUTION_NAMES = new Set([
16
15
  'defineAction',
@@ -4,7 +4,7 @@ import { ambiguity, forbiddenIoImport, hasForbiddenGlobalCall, production, viola
4
4
  import { machineExportStatus, stateMachineConstructorOrigin } from './state-machine.js';
5
5
  const STATE_MODULES = new Set(['@astrale-os/sdk/state']);
6
6
  const FORBIDDEN_LAYERS = new Set([
7
- 'actions',
7
+ 'functions',
8
8
  'integrations',
9
9
  'mutations',
10
10
  'providers',
@@ -12,7 +12,6 @@ const FORBIDDEN_LAYERS = new Set([
12
12
  'rules',
13
13
  'scripts',
14
14
  'views',
15
- 'workflows',
16
15
  ]);
17
16
  export const stateRules = [
18
17
  {
@@ -4,11 +4,13 @@ import { ambiguity, calls, isForeignDomain, production, staticId, violation } fr
4
4
  const STEP_METHODS = new Set(['run']);
5
5
  export const workflowRules = [
6
6
  {
7
- id: 'WFL-INT-TYPES',
8
- ruleRevision: '9e170a6106bc57fe16441c6fb3d7ac4cac22c064c32eefa1118bda275f993a00',
7
+ id: 'FNC-INT-TYPES',
8
+ ruleRevision: 'd7f9733e3724ff3c449203551012b7c37bf7af7d2e0bc5b2642308822601a119',
9
9
  evaluate(project) {
10
10
  const evidence = [];
11
- for (const file of production(project, 'workflows')) {
11
+ for (const file of production(project, 'functions')) {
12
+ if (workflowDefinitions(file).length === 0)
13
+ continue;
12
14
  for (const statement of file.source.statements) {
13
15
  if (ts.isInterfaceDeclaration(statement) &&
14
16
  (statement.name.text.endsWith('Integrations') ||
@@ -21,11 +23,11 @@ export const workflowRules = [
21
23
  },
22
24
  },
23
25
  {
24
- id: 'WFL-STEP-IDS',
25
- ruleRevision: '4f079d31de09852c7f5a8afcd5ca77959c905e76d6a771e0105f26d4bec5bc47',
26
+ id: 'FNC-STEP-IDS',
27
+ ruleRevision: '98f082909d0df405d36e17218d266cd7eacbfb8ce6dd42efa565fa02df64d43c',
26
28
  evaluate(project) {
27
29
  const evidence = [];
28
- for (const file of production(project, 'workflows')) {
30
+ for (const file of production(project, 'functions')) {
29
31
  for (const definition of workflowDefinitions(file)) {
30
32
  if (definition.origin === 'ambiguous') {
31
33
  evidence.push(ambiguity(file, definition.call, 'Workflow definition resolves through a local facade whose ultimate public constructor origin is unknown.'));
@@ -64,11 +66,11 @@ export const workflowRules = [
64
66
  },
65
67
  },
66
68
  {
67
- id: 'WFL-XDOM-INT',
68
- ruleRevision: 'e526868b72d44fb5d88beb61937fce9f6e90c8418381ac34e9e5a01efc1e3dee',
69
+ id: 'FNC-XDOM-INT',
70
+ ruleRevision: 'ae5a879a6b19e26e33568cc47e0f5c34ba741df0e5dec663590923ceac4de264',
69
71
  evaluate(project) {
70
72
  const evidence = [];
71
- for (const file of production(project, 'workflows')) {
73
+ for (const file of production(project, 'functions')) {
72
74
  for (const sourceImport of file.imports) {
73
75
  if (isForeignDomain(sourceImport.specifier)) {
74
76
  evidence.push(violation(file, sourceImport.node, `Workflow imports foreign Domain ${sourceImport.specifier}; use an Integration.`));
@@ -96,11 +98,11 @@ export const workflowRules = [
96
98
  },
97
99
  },
98
100
  {
99
- id: 'WFL-NO-NEST',
100
- ruleRevision: '1e4026f0ed8b32c9f21f0ac89fed0bd4a6eb92af1328c9781edc16edad300737',
101
+ id: 'FNC-NO-NEST',
102
+ ruleRevision: 'f2d818d1da69830c9ccaf183c5eb0310c795ab5da1a67871952aef1c2ef7600c',
101
103
  evaluate(project) {
102
104
  const evidence = [];
103
- for (const file of production(project, 'workflows')) {
105
+ for (const file of production(project, 'functions')) {
104
106
  const helpers = localFunctions(file.source);
105
107
  for (const definition of workflowDefinitions(file)) {
106
108
  if (definition.origin === 'ambiguous') {
@@ -1,7 +1,7 @@
1
1
  /** Generated from the validated Domain knowledge catalog. Regenerate with pnpm sync:linter-policy. */
2
- export const domainPolicyDigest = '59f23965431ba54e0e4674d8357c69d7662fd537f5ce282513f0b03be935ec8a';
2
+ export const domainPolicyDigest = '21e6086254982ac49fad6bcb8cb3b9997680bcd13adc15f019953224c38a7fe9';
3
3
  export const domainPolicySource = Object.freeze({
4
- rules: "id\tscope\tkind\tseverity\tmessage\tverification\texample\nOWN-SEMANTIC\townership\tarchitecture\terror\tEvery semantic fact, rule, representation, transition, and failure meaning has exactly one owner\tInventory declarations by meaning and report each duplicate authority or ownerless concept\tsemantic-owner.md\nMOD-SUBMODULE\tmodules\tstructure\terror\tEvery semantic source file lives in a dedicated semantic submodule or its registered layer facade\tClassify every layer-root source file and report files outside the registered facade or public index\tsemantic-owner.md\nMOD-REQUIRED\tmodules\tstructure\terror\tEvery required layer and root file declared by the injected layout exists\tCompare admitted project entries with required layout entries and report each missing path\trequired-layout.md\nMOD-GOVERNED\tmodules\tstructure\terror\tEvery source file admitted by the Domain compilation scope belongs to a declared layer or supported root\tClassify admitted source paths after declared workspace and tooling delegation and report each unowned path\tgoverned-source.md\nROOT-FACADE\troots\tstructure\terror\tEvery registered layer facade is exposed through a curated public index\tInspect each layer index and facade and report private-owner behavior or misplaced facade declarations\tpackage-facade.md\nROOT-COMPOSE\troots\tstructure\terror\tPackage roots compose only policy-backed Schema, Runtime, frontend deployment, native Routes, Migrations, Provider-backed Integrations, and supported package journeys\tInspect declared composition and package roots and report behavior, provider protocol logic, recursive barrels, or unsupported exports\tcomposition-root.md\nROOT-PACKAGE\troots\tevidence\terror\tEvery public Schema package subpath maps one admitted source entrypoint to its deterministic published declaration and JavaScript targets\tCompare source and publish exports and reject missing duplicate non-Schema locally linked generated or Kernel-leaking package artifacts\tmulti-domain-package.md\nDEP-ALLOWLIST\tdependencies\tdependency\terror\tEvery direct cross-layer import and its runtime or type-only kind appears in the dependency allowlist and dependencies between distinct layers are acyclic\tResolve source imports, reject every absent or kind-mismatched edge, and detect cycles after excluding evidence edges\tsemantic-owner.md\nIMP-FACADE\timports\tdependency\terror\tEvery cross-submodule import uses the semantic owner's facade and every foreign Domain import uses its public package facade\tResolve imports and report private deep paths outside the importing submodule\tcross-domain.md\nIMP-SDK-BOUNDARY\timports\tdependency\terror\tDomain source imports Kernel Core and DSL authoring values only through semantic SDK subpaths\tInspect every static and literal dynamic import and report module specifiers rooted at @astrale-os/kernel-core or @astrale-os/kernel-dsl\tsdk-boundary.md\nIMP-LAYER-ALIAS\timports\tdependency\terror\tEvery local import crossing a layer or semantic-submodule boundary uses the registered # layer alias\tResolve relative imports and report each one whose target leaves the importing semantic submodule\tlayer-aliases.md\nIMP-ALIAS-CFG\timports\tdependency\terror\tPackage and TypeScript resolution exactly implement each active layer-facade and semantic-submodule alias\tCompare active and required layers with the injected alias registry and report missing, undeclared, or drifted mappings\talias-configuration.md\nIMP-STATIC\timports\tdependency\terror\tProduction dependency edges use analyzable static ESM declarations or literal import calls\tReject require calls, import-equals declarations, nonliteral import calls, and unresolved static dependency forms\tstatic-imports.md\nTYP-OWNER\ttypes\tarchitecture\terror\tEvery type and reusable expected error is colocated with the semantic concept that defines its meaning\tTrace each declaration to its semantic authority and report catch-all or remotely owned values\texpected-failure.md\nERR-EXPECTED\terrors\tdataflow\terror\tBoundaries map only declared expected failures and propagate unexpected defects\tInspect catches and result mappings and report broad fallback, swallowed defects, or mappings without a declared source failure\texpected-failure.md\nTST-NO-PROD-IMP\ttests\tdependency\terror\tProduction source imports no root or colocated Test artifact\tResolve production imports and report targets under Root Tests, __tests__, or test, spec, bench, and perf source files\ttest-import-boundary.md\nABS-EARNED\tabstractions\tarchitecture\terror\tAn invariant or real boundary earns an abstraction; reuse alone requires two independent consumers and no duplicated semantic behavior\tIdentify the invariant, boundary, or independent consumers for each abstraction and report reuse wrappers that duplicate an owner's semantics\tsemantic-owner.md\nABS-NO-REPO\tabstractions\tarchitecture\terror\tDomain source places no collection-shaped persistence facade between business code and canonical Query or Mutation definitions\tInspect persistence-facing contracts and report abstractions that replace graph identity, traversal, observation, or atomic change semantics\tsemantic-owner.md\nABS-CANON-GRAPH\tabstractions\tdeclaration\terror\tDomain source declares no alternate Query or Mutation language, AST, compiler, planner, or wire representation\tInspect graph-related declarations and report semantics not identical to canonical Kernel Query or Mutation values\tsemantic-owner.md\nTRUST-ADMIT-ONCE\ttrust\tdataflow\terror\tEvery untrusted value is admitted or translated exactly once at its owning boundary\tTrace values from each external boundary and report missing admission or repeated structural validation\texpected-failure.md\nQLT-EXHAUSTIVE\tquality\tbehavior\terror\tEvery closed alternative is handled exhaustively and no required failure becomes placeholder success\tTrace closed unions and failure paths and report permissive defaults, placeholder success, or catch-and-continue behavior\texpected-failure.md\nQLT-CANON-VALUES\tquality\tdataflow\terror\tNo unchecked cast fabricates a canonical Kernel identity, QueryAST, MutationAST, or admitted schema value\tScan casts to canonical values and require an owning constructor or decoder for each\tsemantic-owner.md\nQLT-DEF-IDS\tquality\tdeclaration\terror\tEvery top-level Query, Mutation, and Migration definition has a stable literal ID unique in its owning namespace\tExtract top-level definition IDs and report missing, dynamic, malformed, or duplicate values\tdefinition-identities.md\nQLT-TYPED-COORD\tquality\tdeclaration\terror\tQueries and Mutations derive graph coordinates from resolved DSL definitions instead of raw string or structural reconstruction\tReject raw PropertyKey calls and structural ClassPath objects; require canonical resolved Classes Properties and keys at graph boundaries\ttyped-coordinates.md\nNODE-INHERITED\tnodes\tdeclaration\terror\tNo Node Class redeclares name, description, createdAt, or updatedAt inherited from Named, Descriptable, and Timestamped\tScan Node Class Properties and report each inherited field redeclaration\tsemantic-owner.md\nDOM-PUBLIC-DEPS\tdomains\tdependency\terror\tEvery directly referenced foreign-Domain graph declaration has one exact Schema dependency\tResolve foreign Schema, Query, and Mutation graph references and report each package without one exact declared Schema dependency\tcross-domain.md\nDOM-CALL-INT\tdomains\tdependency\terror\tEvery cross-Domain callable invocation implements a consumer-owned Integration inside a Provider and uses only the remote Domain's public facade\tTrace foreign callable invocations and report direct Action or Workflow calls, missing Integration contracts, non-Provider call sites, or private remote imports\tremote-domain-call.md\nDOM-ATOMICITY\tdomains\tbehavior\terror\tA cross-Domain change claims atomicity only when it is one MutationAST on one graph; calls combined with other effects are Workflow steps\tTrace atomicity and effect claims and report multiple commits, service boundaries, or foreign calls combined in a Action\tcross-domain.md\nSCH-SUBMODULE\tschema\tdeclaration\terror\tEvery authored declaration and public callable value has exactly one Schema submodule owner\tInventory declarations and callable inputs, results, and failures and report missing, duplicate, or layer-root owners\tschema-facade.md\nSCH-DECL-ONLY\tschema\tdeclaration\terror\tSchema performs no handler execution, Query execution, Mutation submission, Integration call, Workflow step, or Provider call\tResolve Schema imports and call graphs and require zero excluded operations\tpublication-callables.md\nSCH-EXACT-TYPES\tschema\tdeclaration\terror\tSchema authoring values preserve their exact inferred DSL types instead of widening to generic builder contracts\tScan Schema declarations and action returns for explicit generic builder authoring annotations\tschema-facade.md\nSCH-POLICY-AUTH\tschema\tdeclaration\terror\tCallable authority is declared through Policy and Action implementations add no private authorization rule\tTrace callable admission and report authority conditions without one owning Policy\tpolicy.md\nSCH-STATE-SOURCE\tschema\tdeclaration\terror\tEvery persisted StateMachine vocabulary originates from an exported authority in the same Schema business module rather than a copied literal set\tResolve exact StateMachine and stateProperty origins; report same-owner copied literals and reject cross-module association\tarticle-schema.md\nSCH-STATE-RELATION\tschema\tdeclaration\terror\tEvery StateMachine is one exported static immutable finite relation without parallel vocabulary authorities\tInspect Schema module machines and exported sibling values for split or copied topology\tarticle-status.md\nSCH-STATE-PURE\tschema\tdeclaration\terror\tStateMachine topology contains no behavior, effects, guards, clocks, retry, recovery, or orchestration\tInspect files that declare StateMachine authorities for behavioral exports, boundary imports, and effectful calls\tstate-pure.md\nRUL-SYNC\trules\tbehavior\terror\tEvery Rule is synchronous and returns no Promise, continuation, generator, or asynchronous iterator\tInspect Rule signatures and result types and reject asynchronous forms\tnormalization.md\nRUL-PURE\trules\tbehavior\terror\tRules perform no I/O and depend on no graph executor or Domain execution boundary\tResolve imports and effect origins, permitting pure standard value transformations while reporting conclusive I/O and Domain execution dependencies\tpublish-eligibility.md\nRUL-EXPL-FACTS\trules\tbehavior\terror\tEvery clock value, random value, identity, limit, and environmental observation used by a Rule is an explicit input\tTrace every value source and report reads from ambient state, globals, process state, or hidden singletons\ttime-facts.md\nRUL-CLOSED-DEC\trules\tbehavior\terror\tEvery expected business alternative is represented by a closed decision value rather than thrown control flow\tInspect Rule branches and report expected alternatives represented by exceptions or open optional fields\tpublish-eligibility.md\nQRY-CANON\tqueries\tdataflow\terror\tEvery graph request produced by a Query definition is one canonical QueryAST built through Kernel Query APIs\tTrace request construction and reject every non-canonical graph document\tfiltered-query.md\nQRY-CONTRACT\tqueries\tdataflow\terror\tA Query owns its input, observation, optional business projection, pagination, and expected failures\tInspect each Query definition and report a required concern owned elsewhere or omitted\tquery-transforms.md\nQRY-SINGLE\tqueries\tdataflow\terror\tEvery authored single Query definition declares exactly one build callback and at most one project callback\tInspect definition properties and canonical roots; report opaque helper origins as ambiguity rather than assuming cardinality\tsingle-query.md\nQRY-COMPOSE-TYPED\tqueries\tdataflow\terror\tA composite Query constructs one closed QueryPlan containing only typed single-Query leaves, symbolic output references, and explicit result composition\tInspect plan construction, report unresolved call origins as ambiguity, and reject nested composites, raw sessions, graph clients, result-time callbacks, arbitrary promises, or Domain effects\tdependent-query.md\nQRY-COMPOSE-STABLE\tqueries\tdeclaration\terror\tEvery composite Query leaf has a stable semantic literal ID unique within its definition\tInspect declared Query leaves and reject dynamic, malformed, or duplicate leaf identifiers\tdependent-query.md\nQRY-COLL-FANOUT\tqueries\tdataflow\twarning\tThree or more independent same-kind complete-Class collection leaves use one explicit query.union group\tInfer collection kind from canonical definition types and print the direct named replacement plus logical and physical plan counts\tcollection-union.md\nQRY-PROJECT-PURE\tqueries\tdataflow\terror\tEvery Query project callback is synchronous and performs only pure value transformation\tInspect project callback syntax and call graphs and report asynchronous continuation, I/O, mutation, nondeterminism, hidden query execution, or effects\tprojection.md\nQRY-SNAPSHOT\tqueries\tdataflow\terror\tA composite or paginated Query makes no point-in-time graph snapshot claim beyond one Kernel invocation\tReject shared-snapshot claims across leaves unions or continuations and route stronger consistency to an explicit Kernel facility\tdependent-query.md\nMUT-CANON\tmutations\tdataflow\terror\tEvery Mutation definition builds one synchronous change through the canonical builder and constructs no alternate or nested graph document\tInspect every definition build callback and reject missing, asynchronous, alternate, or nested Mutation construction\tatomic-mutation.md\nMUT-CONTRACT\tmutations\tdataflow\terror\tA Mutation owns its input, preconditions, operations, optional business projection, and expected failures\tInspect each definition and report required mutation semantics owned elsewhere or omitted\tcreate-aggregate.md\nMUT-PRECONDS\tmutations\tdataflow\terror\tRules decide eligibility and every live graph condition required for safety is encoded as a precondition in the same MutationAST\tMap decisions to preconditions and report duplicated eligibility or safety enforced only by an earlier observation\tconditional-update.md\nMUT-FRAGMENTS\tmutations\tdataflow\terror\tReusable fragments receive the callback-scoped MutationBuilder and contribute only to the same MutationAST\tResolve fragment signatures and calls and reject escaped builders, opaque documents, or nested MutationAST construction\tmutation-fragments.md\nMUT-PURE\tmutations\tdataflow\terror\tMutation definitions perform no session call, external effect, retry, compensation, or second submission\tScan definition call graphs and require zero excluded operations\tedge-change.md\nMUT-MULTI-WFL\tmutations\tdataflow\terror\tA change requiring several MutationAST values is a Workflow and is never exposed as one atomic Mutation\tTrace multi-commit changes and report definitions or names claiming single-mutation atomicity\tdelete-node.md\nMUT-STATE-INITIAL\tmutations\tdataflow\terror\tEvery StateMachine-backed node is created from its machine's initial state\tResolve machine-backed Property initializers and require the canonical machine.initial value rather than a copied state literal\tstate-transition.md\nMUT-STATE-ATOMIC\tmutations\tdataflow\terror\tEvery persisted machine-state change consumes one allowed decision and commits its stale-state precondition and update in the same MutationAST\tInspect machine-backed writes and require transition with the canonical Schema module machine and one allowed decision; reject direct target writes and split precondition updates\tstate-transition.md\nWFL-MULTISTEP\tworkflows\tbehavior\terror\tEvery Workflow definition contains at least two distinct semantic asynchronous operation sites\tInventory operation sites in the definition and report fewer than two; early exit, rejection, and recovery paths may execute fewer\tpublication-workflow.md\nWFL-STEP-EFFECTS\tworkflows\tbehavior\terror\tEvery semantic asynchronous operation maps to one named step.run boundary\tTrace effects and report operations outside step.run\tpublication-workflow.md\nWFL-STEP-IDS\tworkflows\tbehavior\terror\tEvery step identifier is a stable non-empty kebab-case literal unique within its Workflow\tExtract step identifiers and reject dynamic, malformed, empty, or duplicate values\tpublication-workflow.md\nWFL-NO-NEST\tworkflows\tbehavior\terror\tNo step.run callback invokes another step.run directly or through a reachable helper\tInspect callback call graphs and report every nested step.run path\tpublication-workflow.md\nWFL-INT-TYPES\tworkflows\tdeclaration\terror\tWorkflow Integration requirements derive from declared Integration definitions and the SDK projects their clients\tReject Workflow-owned operation interfaces and require its definition generic to reference the declared Integration registry\tcross-domain-workflow.md\nWFL-ONE-OP-STEP\tworkflows\tbehavior\terror\tEvery step owns exactly one semantic asynchronous operation\tTrace each step and report zero or several independently failing operations\tpublication-workflow.md\nWFL-STATE-CODEC\tworkflows\tbehavior\terror\tEvery step result and inter-step value is undefined or portable JSON data\tInspect step values and report actions, clients, symbols, bigint, cycles, or class instances\tpublication-workflow.md\nWFL-RECOVERY\tworkflows\tbehavior\terror\tWhen compensation or unknown-outcome branches exist, they are explicit and rely only on declared operation semantics\tInspect existing recovery branches and report guessed outcomes or compensation without exact evidence\tpublication-workflow.md\nWFL-XDOM-INT\tworkflows\tbehavior\terror\tA Workflow invokes another Domain only through a declared Integration and imports no foreign Domain\tResolve Workflow imports and operations and report foreign Domain imports or calls without Integration ownership\tcross-domain-workflow.md\nMIG-EXACT-REVS\tmigrations\tdataflow\terror\tEvery Migration declares exactly one source revision and one target revision for the same Domain origin\tParse Migration descriptors and reject missing, equal, ambiguous, cross-origin, or dynamically selected revisions\texact-revisions.md\nMIG-APP-DATA\tmigrations\tdataflow\terror\tMigrations transform application-owned facts only and own no schema projection, physical representation, deployment, backup, or external import\tClassify every transformed value and operation and report responsibilities outside application data\trewrite-values.md\nMIG-DEDICATED-CTX\tmigrations\tdataflow\terror\tMigration execution uses only its dedicated source reader, target writer, durable step context, revision-compatible Rules, and generic Utils\tResolve imports and calls and reject ordinary Actions, Workflows, Queries, Mutations, Integrations, Providers, Views, UI, or provider access\texact-revisions.md\nMIG-RESTART-SAFE\tmigrations\tdataflow\terror\tEvery Migration page is idempotent and resumes from a stable checkpoint without reinterpreting accepted target output\tInterrupt before and after every page commit, resume repeatedly, and compare target facts and checkpoints with uninterrupted execution\trestart-safe.md\nMIG-TARGET-PROOF\tmigrations\tdataflow\terror\tA Migration completes only after bounded source coverage and target-revision validation account for every selected source fact\tInject omitted, duplicated, invalid, and over-budget facts and require completion to fail with exact evidence\tverify-target.md\nMIG-DESTRUCTIVE\tmigrations\tdataflow\terror\tEvery destructive or irreversible transform declares and accounts for its intended loss and exposes declared expected failures\tTrace removals and irreversible rewrites and report undeclared or unaccounted loss, open failures, or catch-and-continue behavior\tremove-facts.md\nINT-BOUNDARY\tintegrations\tarchitecture\terror\tEvery Integration represents required behavior across an external, remote-Domain, substitution, process, or trust boundary\tIdentify the boundary for every contract and report behavior that can remain ordinary local Domain code\tpayment-authorization.md\nINT-NEUTRAL\tintegrations\tdeclaration\terror\tEvery Integration owns provider-neutral requests, evidence, correlation, idempotency, trust, and expected failure semantics needed by consumers\tInspect consumers and contracts and report provider fields or missing stable boundary semantics\tid-allocation.md\nINT-PURE\tintegrations\tdependency\terror\tIntegrations remain provider- and execution-boundary-neutral and import no concrete client, credential, configuration, Provider, Action, or Workflow\tResolve runtime and provider imports and report every conclusive concrete or execution-boundary dependency\tdocument-signing.md\nINT-ABILITY-NAME\tintegrations\tstructure\terror\tIntegration submodules are named by required ability and never mirror Schema entities mechanically\tCompare Integration and Schema submodules and report a contract without an independent boundary ability\tobject-storage.md\nACT-ONE-IMPL\tactions\tbehavior\terror\tEvery registered handler binding resolves to exactly one implementation owned by one semantic Actions submodule\tResolve the handler registry and report non-Action owners or duplicate registrations; SDK typing owns callable exhaustiveness\tsynchronous-result.md\nACT-ONE-OP\tactions\tbehavior\terror\tEvery Action performs one terminal semantic operation; only a native binary compatibility Action may precede its Integration call with one exact-receiver Query\tTrace every path and report several terminal effects, writes before effects, non-receiver prerequisite reads, or hidden orchestration\tsingle-operation.md\nACT-OP-KINDS\tactions\tbehavior\terror\tA semantic asynchronous operation is one Query definition, Mutation definition, or Integration call\tClassify every awaited effect and report operations outside the three allowed kinds\tintegration-operation.md\nACT-BOUNDARIES\tactions\tbehavior\terror\tActions use only invocation-bound query and mutate executors, including explicit caller self or union graph partitions, plus declared Integrations; Providers or foreign Domains are never imported\tInspect context use, authority-mode selection, dependencies, imports, and failure mapping; report raw or unbound graph executors, implicit privilege, concrete or foreign dependencies, broad mapping, or swallowed defects\tremote-integration.md\nACT-BINARY-RESULT\tactions\tbehavior\terror\tA binary Action returns detached buffered bytes or streaming bytes with admitted media type status and application headers without collecting or value-framing a provider stream\tExercise buffered and streaming results through their native route; verify exact bytes status headers cancellation and invalid output rejection\tnative-byte-response.md\nRTE-RECIPE\troutes\tdeclaration\terror\tEvery native HTTP Route targets exactly one admitted Action or Workflow recipe\tResolve every route target and report forged missing or several recipes\taction-route.md\nRTE-MAPPING\troutes\tdataflow\terror\tEvery callable input field and instance receiver is mapped exactly once from path query header method or body input\tCompile each route against its resolved callable and reject incomplete ambiguous or unknown mappings\tinstance-route.md\nRTE-CREDENTIAL\troutes\tdataflow\terror\tEvery external credential source is explicit and is never also mapped as callable input\tCompile credential and input mappings and reject duplicate reserved or implicit authority sources\tcredential-route.md\nRTE-ONE-FILE\troutes\tstructure\terror\tEvery Route declaration has one business-intent kebab-case file and Routes composition contains no inline declaration\tInventory route declarations and report generic grouped or inline ownership\tapplication-routes.md\nPRV-INT-IMPL\tproviders\tarchitecture\terror\tEvery Provider implements one or more declared Integrations across a named external or remote-Domain boundary\tIdentify the boundary and implemented contracts and report a Provider without both\tpayment-provider.md\nPRV-BOUNDARY-NAME\tproviders\tstructure\terror\tProvider submodules are named by external system, protocol, or trust boundary rather than Domain entity\tInspect every submodule name and report one justified only by Schema vocabulary\tobject-storage-provider.md\nPRV-ADMIT-RESULT\tproviders\tdataflow\terror\tEvery boundary value is admitted before Integration evidence and recognized boundary failures become stable Integration failures\tTrace input and failure paths and report missing admission, leaked boundary errors, broad mapping, or swallowed defects\twebhook-admission.md\nPRV-NO-DOMAIN\tproviders\tdependency\terror\tProviders perform no local Domain graph operation, business decision, local Action call, or Workflow orchestration\tResolve Provider imports and call graphs and require zero excluded operations\tboundary-composition.md\nPRV-XDOM-TYPED\tproviders\tdependency\terror\tRemote-Domain Providers pass SDK-derived typed callable references to the caller-bound invocation capability without never casts\tInspect Provider execution invoke calls and reject references not constructed through SDK reference, opaque or fabricated references, and never-cast arguments\tremote-domain.md\nPRV-XDOM-REQ\tproviders\tdependency\terror\tEvery statically resolved remote-Domain Provider invocation has one exact Application Function requirement\tMatch each invocation-bound public callable reference to the same foreign facade and Function selector under Application requirements; preserve opaque references or composition as indeterminate\tremote-domain.md\nPRV-XDOM-PUBLIC\tproviders\tdependency\terror\tA remote-Domain Provider uses the remote public facade and invokes at most one public callable per Integration operation\tResolve receiver and facade origins for each remote operation and report private access, missing Integration ownership, unrelated calls, or several public invocations\tremote-domain.md\nVIW-PROJECTION\tviews\tdeclaration\terror\tEvery View converts public Domain values or named Query observations into UI props and connects each action to a named bounded Mutation or public callable contract\tInspect View outputs and actions and report behavior without a Schema, Query, UI, Mutation, Rule, or public callable owner\tdetail-view.md\nVIW-SCHEMA-DECL\tviews\tdeclaration\terror\tSchema owns every DSL View declaration and Views declares no Domain schema construct\tScan View declarations and reject Classes, Properties, Policies, Methods, Actions, or DSL Views\tarticle-list.md\nVIW-NO-COMPOSE\tviews\tdeclaration\terror\tApplication owns frontend deployment composition and Views never calls defineFrontend\tResolve direct imported defineFrontend calls in Views and report SDK constructor calls while ignoring unrelated local functions\tfrontend-composition.md\nVIW-DEPS\tviews\tdependency\terror\tViews import only Schema and its StateMachines, pure Rules, named Queries, bounded named Mutations, UI, shell-react primitives, public callable contracts, and presentation libraries\tInspect resolved imports and report dependencies or raw graph APIs outside the allowlist\tnavigation.md\nVIW-ACTIONS\tviews\tdataflow\terror\tEvery View action executes a named caller-authorized atomic Mutation or invokes a public callable; presentation state is never authorization evidence\tTrace action and authority paths and report inline or raw graph documents, elevated or effectful Mutation use, private Action imports, direct Integration calls, or authority derived from presentation\tform-actions.md\nUI-PRES-DEPS\tui\tdependency\terror\tEvery UI import is a sibling UI module or an external library used only for presentation\tInspect resolved imports and used APIs and report Domain, I/O, persistence, authorization, routing, or provider behavior\tstatus-panel.md\nUI-NO-DOMAIN\tui\tdependency\terror\tUI imports no Domain layer or Domain package facade\tResolve the UI import graph and require zero Domain paths\tresult-list.md\nUI-PURE\tui\tbehavior\terror\tUI performs no I/O, graph access, storage, authorization, business validation, provider call, routing, or Domain result mapping\tInspect components and hooks and report the exact excluded call or branch\tconfirmation-dialog.md\nUI-CALLBACKS\tui\tdataflow\terror\tUI accepts presentation props and forwards intent through callbacks without constructing Domain commands\tInspect props and event handlers and report Domain identities, command construction, or business decisions\tform.md\nUTL-DOM-AGNOSTIC\tutils\tarchitecture\terror\tEvery Utils export is Domain-agnostic and contains no Domain declaration, identity, decision, graph definition, or Workflow step\tInspect signatures and implementations and report the exact Domain concept or business behavior\tresult.md\nUTL-REUSED\tutils\tarchitecture\terror\tEvery Utils extension serves two independent semantic consumers or one package-wide execution boundary\tList direct consumers and report an extension satisfying neither condition\tjson-codec.md\nUTL-PUBLIC-DEPS\tutils\tdependency\terror\tUtils imports only public Kernel, DSL, SDK, standard-library, and sibling Utils modules\tResolve the Utils import graph and reject Domain layers, Providers, or private package paths\tjson-codec.md\nUTL-LIGHTWEIGHT\tutils\tarchitecture\terror\tUtils is private and owns no durable engine, planner, compiler, Repository, service locator, or dependency container\tInspect package exports and declarations and report public exposure or any forbidden framework machinery\tresult.md\nSCR-OPERATOR\tscripts\tbehavior\terror\tEvery root Script implements a supported operator workflow with declared inputs, outcomes, failures, and proof\tInspect each Script contract and report disposable tasks or missing operator semantics\tbackup.md\nSCR-PUBLIC-DEPS\tscripts\tbehavior\terror\tScripts import only dependency-DAG-authorized public facades, standard libraries, and operator libraries and define no Domain behavior\tResolve imports and inspect branches and report private paths, business decisions, graph definitions, or callable behavior\tupgrade.md\nSCR-TEST-DRIVERS\tscripts\tbehavior\terror\tDisposable setup, fixtures, resets, and scenario drivers live under tests/scripts rather than root Scripts\tClassify every Script by supported operator contract and report evidence-only programs at the root\trestore.md\nTST-SYS-OWNER\ttests\tevidence\terror\tRoot Tests owns cross-layer journeys, environments, harnesses, scenarios, seeds, fixtures, and disposable scripts\tInventory evidence support code and report cross-layer artifacts outside Tests or production semantics inside Tests\tmigration-scenario.md\nTST-COLOCATED\ttests\tevidence\terror\tEvery semantic production submodule owns focused evidence in its local __tests__ directory\tJoin production submodules to focused test directories and report missing owners\tfocused-rule.md\n",
4
+ rules: "id\tscope\tkind\tseverity\tmessage\tverification\texample\nOWN-SEMANTIC\townership\tarchitecture\terror\tEvery semantic fact, rule, representation, transition, and failure meaning has exactly one owner\tInventory declarations by meaning and report each duplicate authority or ownerless concept\tsemantic-owner.md\nMOD-SUBMODULE\tmodules\tstructure\terror\tEvery semantic source file lives in a dedicated semantic submodule or its registered layer facade\tClassify every layer-root source file and report files outside the registered facade or public index\tsemantic-owner.md\nMOD-REQUIRED\tmodules\tstructure\terror\tEvery required layer and root file declared by the injected layout exists\tCompare admitted project entries with required layout entries and report each missing path\trequired-layout.md\nMOD-GOVERNED\tmodules\tstructure\terror\tEvery source file admitted by the Domain compilation scope belongs to a declared layer or supported root\tClassify admitted source paths after declared workspace and tooling delegation and report each unowned path\tgoverned-source.md\nROOT-FACADE\troots\tstructure\terror\tEvery registered layer facade is exposed through a curated public index\tInspect each layer index and facade and report private-owner behavior or misplaced facade declarations\tpackage-facade.md\nROOT-COMPOSE\troots\tstructure\terror\tPackage roots compose only policy-backed Schema, Runtime, frontend deployment, native Routes, Migrations, Provider-backed Integrations, and supported package journeys\tInspect declared composition and package roots and report behavior, provider protocol logic, recursive barrels, or unsupported exports\tcomposition-root.md\nROOT-PACKAGE\troots\tevidence\terror\tEvery public Schema package subpath maps one admitted source entrypoint to its deterministic published declaration and JavaScript targets\tCompare source and publish exports and reject missing duplicate non-Schema locally linked generated or Kernel-leaking package artifacts\tmulti-domain-package.md\nDEP-ALLOWLIST\tdependencies\tdependency\terror\tEvery direct cross-layer import and its runtime or type-only kind appears in the dependency allowlist and dependencies between distinct layers are acyclic\tResolve source imports, reject every absent or kind-mismatched edge, and detect cycles after excluding evidence edges\tsemantic-owner.md\nIMP-FACADE\timports\tdependency\terror\tEvery cross-submodule import uses the semantic owner's facade and every foreign Domain import uses its public package facade\tResolve imports and report private deep paths outside the importing submodule\tcross-domain.md\nIMP-SDK-BOUNDARY\timports\tdependency\terror\tDomain source imports Kernel Core and DSL authoring values only through semantic SDK subpaths\tInspect every static and literal dynamic import and report module specifiers rooted at @astrale-os/kernel-core or @astrale-os/kernel-dsl\tsdk-boundary.md\nIMP-LAYER-ALIAS\timports\tdependency\terror\tEvery local import crossing a layer or semantic-submodule boundary uses the registered # layer alias\tResolve relative imports and report each one whose target leaves the importing semantic submodule\tlayer-aliases.md\nIMP-ALIAS-CFG\timports\tdependency\terror\tPackage and TypeScript resolution exactly implement each active layer-facade and semantic-submodule alias\tCompare active and required layers with the injected alias registry and report missing, undeclared, or drifted mappings\talias-configuration.md\nIMP-STATIC\timports\tdependency\terror\tProduction dependency edges use analyzable static ESM declarations or literal import calls\tReject require calls, import-equals declarations, nonliteral import calls, and unresolved static dependency forms\tstatic-imports.md\nTYP-OWNER\ttypes\tarchitecture\terror\tEvery type and reusable expected error is colocated with the semantic concept that defines its meaning\tTrace each declaration to its semantic authority and report catch-all or remotely owned values\texpected-failure.md\nERR-EXPECTED\terrors\tdataflow\terror\tBoundaries map only declared expected failures and propagate unexpected defects\tInspect catches and result mappings and report broad fallback, swallowed defects, or mappings without a declared source failure\texpected-failure.md\nTST-NO-PROD-IMP\ttests\tdependency\terror\tProduction source imports no root or colocated Test artifact\tResolve production imports and report targets under Root Tests, __tests__, or test, spec, bench, and perf source files\ttest-import-boundary.md\nABS-EARNED\tabstractions\tarchitecture\terror\tAn invariant or real boundary earns an abstraction; reuse alone requires two independent consumers and no duplicated semantic behavior\tIdentify the invariant, boundary, or independent consumers for each abstraction and report reuse wrappers that duplicate an owner's semantics\tsemantic-owner.md\nABS-NO-REPO\tabstractions\tarchitecture\terror\tDomain source places no collection-shaped persistence facade between business code and canonical Query or Mutation definitions\tInspect persistence-facing contracts and report abstractions that replace graph identity, traversal, observation, or atomic change semantics\tsemantic-owner.md\nABS-CANON-GRAPH\tabstractions\tdeclaration\terror\tDomain source declares no alternate Query or Mutation language, AST, compiler, planner, or wire representation\tInspect graph-related declarations and report semantics not identical to canonical Kernel Query or Mutation values\tsemantic-owner.md\nTRUST-ADMIT-ONCE\ttrust\tdataflow\terror\tEvery untrusted value is admitted or translated exactly once at its owning boundary\tTrace values from each external boundary and report missing admission or repeated structural validation\texpected-failure.md\nQLT-EXHAUSTIVE\tquality\tbehavior\terror\tEvery closed alternative is handled exhaustively and no required failure becomes placeholder success\tTrace closed unions and failure paths and report permissive defaults, placeholder success, or catch-and-continue behavior\texpected-failure.md\nQLT-CANON-VALUES\tquality\tdataflow\terror\tNo unchecked cast fabricates a canonical Kernel identity, QueryAST, MutationAST, or admitted schema value\tScan casts to canonical values and require an owning constructor or decoder for each\tsemantic-owner.md\nQLT-DEF-IDS\tquality\tdeclaration\terror\tEvery top-level Query, Mutation, and Migration definition has a stable literal ID unique in its owning namespace\tExtract top-level definition IDs and report missing, dynamic, malformed, or duplicate values\tdefinition-identities.md\nQLT-TYPED-COORD\tquality\tdeclaration\terror\tQueries and Mutations derive graph coordinates from resolved DSL definitions instead of raw string or structural reconstruction\tReject raw PropertyKey calls and structural ClassPath objects; require canonical resolved Classes Properties and keys at graph boundaries\ttyped-coordinates.md\nNODE-INHERITED\tnodes\tdeclaration\terror\tNo Node Class redeclares name, description, createdAt, or updatedAt inherited from Named, Descriptable, and Timestamped\tScan Node Class Properties and report each inherited field redeclaration\tsemantic-owner.md\nDOM-PUBLIC-DEPS\tdomains\tdependency\terror\tEvery directly referenced foreign-Domain graph declaration has one exact Schema dependency\tResolve foreign Schema, Query, and Mutation graph references and report each package without one exact declared Schema dependency\tcross-domain.md\nDOM-CALL-INT\tdomains\tdependency\terror\tEvery cross-Domain callable invocation implements a consumer-owned Integration inside a Provider and uses only the remote Domain's public facade\tTrace foreign callable invocations and report direct Action or Workflow calls, missing Integration contracts, non-Provider call sites, or private remote imports\tremote-domain-call.md\nDOM-ATOMICITY\tdomains\tbehavior\terror\tA cross-Domain change claims atomicity only when it is one MutationAST on one graph; calls combined with other effects are Workflow steps\tTrace atomicity and effect claims and report multiple commits, service boundaries, or foreign calls combined in a Action\tcross-domain.md\nSCH-SUBMODULE\tschema\tdeclaration\terror\tEvery authored declaration and public callable value has exactly one Schema submodule owner\tInventory declarations and callable inputs, results, and failures and report missing, duplicate, or layer-root owners\tschema-facade.md\nSCH-DECL-ONLY\tschema\tdeclaration\terror\tSchema performs no handler execution, Query execution, Mutation submission, Integration call, Workflow step, or Provider call\tResolve Schema imports and call graphs and require zero excluded operations\tpublication-callables.md\nSCH-EXACT-TYPES\tschema\tdeclaration\terror\tSchema authoring values preserve their exact inferred DSL types instead of widening to generic builder contracts\tScan Schema declarations and action returns for explicit generic builder authoring annotations\tschema-facade.md\nSCH-POLICY-AUTH\tschema\tdeclaration\terror\tCallable authority is declared through Policy and Action implementations add no private authorization rule\tTrace callable admission and report authority conditions without one owning Policy\tpolicy.md\nSCH-STATE-SOURCE\tschema\tdeclaration\terror\tEvery persisted StateMachine vocabulary originates from an exported authority in the same Schema business module rather than a copied literal set\tResolve exact StateMachine and stateProperty origins; report same-owner copied literals and reject cross-module association\tarticle-schema.md\nSCH-STATE-RELATION\tschema\tdeclaration\terror\tEvery StateMachine is one exported static immutable finite relation without parallel vocabulary authorities\tInspect Schema module machines and exported sibling values for split or copied topology\tarticle-status.md\nSCH-STATE-PURE\tschema\tdeclaration\terror\tStateMachine topology contains no behavior, effects, guards, clocks, retry, recovery, or orchestration\tInspect files that declare StateMachine authorities for behavioral exports, boundary imports, and effectful calls\tstate-pure.md\nRUL-SYNC\trules\tbehavior\terror\tEvery Rule is synchronous and returns no Promise, continuation, generator, or asynchronous iterator\tInspect Rule signatures and result types and reject asynchronous forms\tnormalization.md\nRUL-PURE\trules\tbehavior\terror\tRules perform no I/O and depend on no graph executor or Domain execution boundary\tResolve imports and effect origins, permitting pure standard value transformations while reporting conclusive I/O and Domain execution dependencies\tpublish-eligibility.md\nRUL-EXPL-FACTS\trules\tbehavior\terror\tEvery clock value, random value, identity, limit, and environmental observation used by a Rule is an explicit input\tTrace every value source and report reads from ambient state, globals, process state, or hidden singletons\ttime-facts.md\nRUL-CLOSED-DEC\trules\tbehavior\terror\tEvery expected business alternative is represented by a closed decision value rather than thrown control flow\tInspect Rule branches and report expected alternatives represented by exceptions or open optional fields\tpublish-eligibility.md\nQRY-CANON\tqueries\tdataflow\terror\tEvery graph request produced by a Query definition is one canonical QueryAST built through Kernel Query APIs\tTrace request construction and reject every non-canonical graph document\tfiltered-query.md\nQRY-CONTRACT\tqueries\tdataflow\terror\tA Query owns its input, observation, optional business projection, pagination, and expected failures\tInspect each Query definition and report a required concern owned elsewhere or omitted\tquery-transforms.md\nQRY-SINGLE\tqueries\tdataflow\terror\tEvery authored single Query definition declares exactly one build callback and at most one project callback\tInspect definition properties and canonical roots; report opaque helper origins as ambiguity rather than assuming cardinality\tsingle-query.md\nQRY-COMPOSE-TYPED\tqueries\tdataflow\terror\tA composite Query constructs one closed QueryPlan containing only typed single-Query leaves, symbolic output references, and explicit result composition\tInspect plan construction, report unresolved call origins as ambiguity, and reject nested composites, raw sessions, graph clients, result-time callbacks, arbitrary promises, or Domain effects\tdependent-query.md\nQRY-COMPOSE-STABLE\tqueries\tdeclaration\terror\tEvery composite Query leaf has a stable semantic literal ID unique within its definition\tInspect declared Query leaves and reject dynamic, malformed, or duplicate leaf identifiers\tdependent-query.md\nQRY-COLL-FANOUT\tqueries\tdataflow\twarning\tThree or more independent same-kind complete-Class collection leaves use one explicit query.union group\tInfer collection kind from canonical definition types and print the direct named replacement plus logical and physical plan counts\tcollection-union.md\nQRY-PROJECT-PURE\tqueries\tdataflow\terror\tEvery Query project callback is synchronous and performs only pure value transformation\tInspect project callback syntax and call graphs and report asynchronous continuation, I/O, mutation, nondeterminism, hidden query execution, or effects\tprojection.md\nQRY-SNAPSHOT\tqueries\tdataflow\terror\tA composite or paginated Query makes no point-in-time graph snapshot claim beyond one Kernel invocation\tReject shared-snapshot claims across leaves unions or continuations and route stronger consistency to an explicit Kernel facility\tdependent-query.md\nMUT-CANON\tmutations\tdataflow\terror\tEvery Mutation definition builds one synchronous change through the canonical builder and constructs no alternate or nested graph document\tInspect every definition build callback and reject missing, asynchronous, alternate, or nested Mutation construction\tatomic-mutation.md\nMUT-CONTRACT\tmutations\tdataflow\terror\tA Mutation owns its input, preconditions, operations, optional business projection, and expected failures\tInspect each definition and report required mutation semantics owned elsewhere or omitted\tcreate-aggregate.md\nMUT-PRECONDS\tmutations\tdataflow\terror\tRules decide eligibility and every live graph condition required for safety is encoded as a precondition in the same MutationAST\tMap decisions to preconditions and report duplicated eligibility or safety enforced only by an earlier observation\tconditional-update.md\nMUT-FRAGMENTS\tmutations\tdataflow\terror\tReusable fragments receive the callback-scoped MutationBuilder and contribute only to the same MutationAST\tResolve fragment signatures and calls and reject escaped builders, opaque documents, or nested MutationAST construction\tmutation-fragments.md\nMUT-PURE\tmutations\tdataflow\terror\tMutation definitions perform no session call, external effect, retry, compensation, or second submission\tScan definition call graphs and require zero excluded operations\tedge-change.md\nMUT-MULTI-WFL\tmutations\tdataflow\terror\tA change requiring several MutationAST values is a Workflow and is never exposed as one atomic Mutation\tTrace multi-commit changes and report definitions or names claiming single-mutation atomicity\tdelete-node.md\nMUT-STATE-INITIAL\tmutations\tdataflow\terror\tEvery StateMachine-backed node is created from its machine's initial state\tResolve machine-backed Property initializers and require the canonical machine.initial value rather than a copied state literal\tstate-transition.md\nMUT-STATE-ATOMIC\tmutations\tdataflow\terror\tEvery persisted machine-state change consumes one allowed decision and commits its stale-state precondition and update in the same MutationAST\tInspect machine-backed writes and require transition with the canonical Schema module machine and one allowed decision; reject direct target writes and split precondition updates\tstate-transition.md\nFNC-ONE-IMPL\tfunctions\tbehavior\terror\tEvery registered handler binding resolves to exactly one implementation owned by one semantic Functions submodule\tResolve the handler registry and report non-Action owners or duplicate registrations; SDK typing owns callable exhaustiveness\tsynchronous-result.md\nFNC-ONE-OP\tfunctions\tbehavior\terror\tEvery Action performs one terminal semantic operation; only a native binary compatibility Action may precede its Integration call with one exact-receiver Query\tTrace every path and report several terminal effects, writes before effects, non-receiver prerequisite reads, or hidden orchestration\tsingle-operation.md\nFNC-OP-KINDS\tfunctions\tbehavior\terror\tA semantic asynchronous operation is one Query definition, Mutation definition, or Integration call\tClassify every awaited effect and report operations outside the three allowed kinds\tintegration-operation.md\nFNC-BOUNDARIES\tfunctions\tbehavior\terror\tActions use only invocation-bound query and mutate executors, including explicit caller self or union graph partitions, plus declared Integrations; Providers or foreign Domains are never imported\tInspect context use, authority-mode selection, dependencies, imports, and failure mapping; report raw or unbound graph executors, implicit privilege, concrete or foreign dependencies, broad mapping, or swallowed defects\tremote-integration.md\nFNC-BINARY-RESULT\tfunctions\tbehavior\terror\tA binary Action returns detached buffered bytes or streaming bytes with admitted media type status and application headers without collecting or value-framing a provider stream\tExercise buffered and streaming results through their native route; verify exact bytes status headers cancellation and invalid output rejection\tnative-byte-response.md\nFNC-MULTISTEP\tfunctions\tbehavior\terror\tEvery Workflow definition contains at least two distinct semantic asynchronous operation sites\tInventory operation sites in the definition and report fewer than two; early exit, rejection, and recovery paths may execute fewer\tpublication-workflow.md\nFNC-STEP-EFFECTS\tfunctions\tbehavior\terror\tEvery semantic asynchronous operation maps to one named step.run boundary\tTrace effects and report operations outside step.run\tpublication-workflow.md\nFNC-STEP-IDS\tfunctions\tbehavior\terror\tEvery step identifier is a stable non-empty kebab-case literal unique within its Workflow\tExtract step identifiers and reject dynamic, malformed, empty, or duplicate values\tpublication-workflow.md\nFNC-NO-NEST\tfunctions\tbehavior\terror\tNo step.run callback invokes another step.run directly or through a reachable helper\tInspect callback call graphs and report every nested step.run path\tpublication-workflow.md\nFNC-INT-TYPES\tfunctions\tdeclaration\terror\tWorkflow Integration requirements derive from declared Integration definitions and the SDK projects their clients\tReject Workflow-owned operation interfaces and require its definition generic to reference the declared Integration registry\tcross-domain-workflow.md\nFNC-ONE-OP-STEP\tfunctions\tbehavior\terror\tEvery step owns exactly one semantic asynchronous operation\tTrace each step and report zero or several independently failing operations\tpublication-workflow.md\nFNC-STATE-CODEC\tfunctions\tbehavior\terror\tEvery step result and inter-step value is undefined or portable JSON data\tInspect step values and report actions, clients, symbols, bigint, cycles, or class instances\tpublication-workflow.md\nFNC-RECOVERY\tfunctions\tbehavior\terror\tWhen compensation or unknown-outcome branches exist, they are explicit and rely only on declared operation semantics\tInspect existing recovery branches and report guessed outcomes or compensation without exact evidence\tpublication-workflow.md\nFNC-XDOM-INT\tfunctions\tbehavior\terror\tA Workflow invokes another Domain only through a declared Integration and imports no foreign Domain\tResolve Workflow imports and operations and report foreign Domain imports or calls without Integration ownership\tcross-domain-workflow.md\nMIG-EXACT-REVS\tmigrations\tdataflow\terror\tEvery Migration declares exactly one source revision and one target revision for the same Domain origin\tParse Migration descriptors and reject missing, equal, ambiguous, cross-origin, or dynamically selected revisions\texact-revisions.md\nMIG-APP-DATA\tmigrations\tdataflow\terror\tMigrations transform application-owned facts only and own no schema projection, physical representation, deployment, backup, or external import\tClassify every transformed value and operation and report responsibilities outside application data\trewrite-values.md\nMIG-DEDICATED-CTX\tmigrations\tdataflow\terror\tMigration execution uses only its dedicated source reader, target writer, durable step context, revision-compatible Rules, and generic Utils\tResolve imports and calls and reject ordinary Actions, Workflows, Queries, Mutations, Integrations, Providers, Views, UI, or provider access\texact-revisions.md\nMIG-RESTART-SAFE\tmigrations\tdataflow\terror\tEvery Migration page is idempotent and resumes from a stable checkpoint without reinterpreting accepted target output\tInterrupt before and after every page commit, resume repeatedly, and compare target facts and checkpoints with uninterrupted execution\trestart-safe.md\nMIG-TARGET-PROOF\tmigrations\tdataflow\terror\tA Migration completes only after bounded source coverage and target-revision validation account for every selected source fact\tInject omitted, duplicated, invalid, and over-budget facts and require completion to fail with exact evidence\tverify-target.md\nMIG-DESTRUCTIVE\tmigrations\tdataflow\terror\tEvery destructive or irreversible transform declares and accounts for its intended loss and exposes declared expected failures\tTrace removals and irreversible rewrites and report undeclared or unaccounted loss, open failures, or catch-and-continue behavior\tremove-facts.md\nINT-BOUNDARY\tintegrations\tarchitecture\terror\tEvery Integration represents required behavior across an external, remote-Domain, substitution, process, or trust boundary\tIdentify the boundary for every contract and report behavior that can remain ordinary local Domain code\tpayment-authorization.md\nINT-NEUTRAL\tintegrations\tdeclaration\terror\tEvery Integration owns provider-neutral requests, evidence, correlation, idempotency, trust, and expected failure semantics needed by consumers\tInspect consumers and contracts and report provider fields or missing stable boundary semantics\tid-allocation.md\nINT-PURE\tintegrations\tdependency\terror\tIntegrations remain provider- and execution-boundary-neutral and import no concrete client, credential, configuration, Provider, Action, or Workflow\tResolve runtime and provider imports and report every conclusive concrete or execution-boundary dependency\tdocument-signing.md\nINT-ABILITY-NAME\tintegrations\tstructure\terror\tIntegration submodules are named by required ability and never mirror Schema entities mechanically\tCompare Integration and Schema submodules and report a contract without an independent boundary ability\tobject-storage.md\nRTE-RECIPE\troutes\tdeclaration\terror\tEvery native HTTP Route targets exactly one admitted Action or Workflow recipe\tResolve every route target and report forged missing or several recipes\taction-route.md\nRTE-MAPPING\troutes\tdataflow\terror\tEvery callable input field and instance receiver is mapped exactly once from path query header method or body input\tCompile each route against its resolved callable and reject incomplete ambiguous or unknown mappings\tinstance-route.md\nRTE-CREDENTIAL\troutes\tdataflow\terror\tEvery external credential source is explicit and is never also mapped as callable input\tCompile credential and input mappings and reject duplicate reserved or implicit authority sources\tcredential-route.md\nRTE-ONE-FILE\troutes\tstructure\terror\tEvery Route declaration has one business-intent kebab-case file and Routes composition contains no inline declaration\tInventory route declarations and report generic grouped or inline ownership\tapplication-routes.md\nPRV-INT-IMPL\tproviders\tarchitecture\terror\tEvery Provider implements one or more declared Integrations across a named external or remote-Domain boundary\tIdentify the boundary and implemented contracts and report a Provider without both\tpayment-provider.md\nPRV-BOUNDARY-NAME\tproviders\tstructure\terror\tProvider submodules are named by external system, protocol, or trust boundary rather than Domain entity\tInspect every submodule name and report one justified only by Schema vocabulary\tobject-storage-provider.md\nPRV-ADMIT-RESULT\tproviders\tdataflow\terror\tEvery boundary value is admitted before Integration evidence and recognized boundary failures become stable Integration failures\tTrace input and failure paths and report missing admission, leaked boundary errors, broad mapping, or swallowed defects\twebhook-admission.md\nPRV-NO-DOMAIN\tproviders\tdependency\terror\tProviders perform no local Domain graph operation, business decision, local Action call, or Workflow orchestration\tResolve Provider imports and call graphs and require zero excluded operations\tboundary-composition.md\nPRV-XDOM-TYPED\tproviders\tdependency\terror\tRemote-Domain Providers pass SDK-derived typed callable references to the caller-bound invocation capability without never casts\tInspect Provider execution invoke calls and reject references not constructed through SDK reference, opaque or fabricated references, and never-cast arguments\tremote-domain.md\nPRV-XDOM-REQ\tproviders\tdependency\terror\tEvery statically resolved remote-Domain Provider invocation has one exact Application Function requirement\tMatch each invocation-bound public callable reference to the same foreign facade and Function selector under Application requirements; preserve opaque references or composition as indeterminate\tremote-domain.md\nPRV-XDOM-PUBLIC\tproviders\tdependency\terror\tA remote-Domain Provider uses the remote public facade and invokes at most one public callable per Integration operation\tResolve receiver and facade origins for each remote operation and report private access, missing Integration ownership, unrelated calls, or several public invocations\tremote-domain.md\nVIW-PROJECTION\tviews\tdeclaration\terror\tEvery View converts public Domain values or named Query observations into UI props and connects each action to a named bounded Mutation or public callable contract\tInspect View outputs and actions and report behavior without a Schema, Query, UI, Mutation, Rule, or public callable owner\tdetail-view.md\nVIW-SCHEMA-DECL\tviews\tdeclaration\terror\tSchema owns every DSL View declaration and Views declares no Domain schema construct\tScan View declarations and reject Classes, Properties, Policies, Methods, Actions, or DSL Views\tarticle-list.md\nVIW-NO-COMPOSE\tviews\tdeclaration\terror\tApplication owns frontend deployment composition and Views never calls defineFrontend\tResolve direct imported defineFrontend calls in Views and report SDK constructor calls while ignoring unrelated local functions\tfrontend-composition.md\nVIW-DEPS\tviews\tdependency\terror\tViews import only Schema and its StateMachines, pure Rules, named Queries, bounded named Mutations, UI, shell-react primitives, public callable contracts, and presentation libraries\tInspect resolved imports and report dependencies or raw graph APIs outside the allowlist\tnavigation.md\nVIW-ACTIONS\tviews\tdataflow\terror\tEvery View action executes a named caller-authorized atomic Mutation or invokes a public callable; presentation state is never authorization evidence\tTrace action and authority paths and report inline or raw graph documents, elevated or effectful Mutation use, private Action imports, direct Integration calls, or authority derived from presentation\tform-actions.md\nUI-PRES-DEPS\tui\tdependency\terror\tEvery UI import is a sibling UI module or an external library used only for presentation\tInspect resolved imports and used APIs and report Domain, I/O, persistence, authorization, routing, or provider behavior\tstatus-panel.md\nUI-NO-DOMAIN\tui\tdependency\terror\tUI imports no Domain layer or Domain package facade\tResolve the UI import graph and require zero Domain paths\tresult-list.md\nUI-PURE\tui\tbehavior\terror\tUI performs no I/O, graph access, storage, authorization, business validation, provider call, routing, or Domain result mapping\tInspect components and hooks and report the exact excluded call or branch\tconfirmation-dialog.md\nUI-CALLBACKS\tui\tdataflow\terror\tUI accepts presentation props and forwards intent through callbacks without constructing Domain commands\tInspect props and event handlers and report Domain identities, command construction, or business decisions\tform.md\nUTL-DOM-AGNOSTIC\tutils\tarchitecture\terror\tEvery Utils export is Domain-agnostic and contains no Domain declaration, identity, decision, graph definition, or Workflow step\tInspect signatures and implementations and report the exact Domain concept or business behavior\tresult.md\nUTL-REUSED\tutils\tarchitecture\terror\tEvery Utils extension serves two independent semantic consumers or one package-wide execution boundary\tList direct consumers and report an extension satisfying neither condition\tjson-codec.md\nUTL-PUBLIC-DEPS\tutils\tdependency\terror\tUtils imports only public Kernel, DSL, SDK, standard-library, and sibling Utils modules\tResolve the Utils import graph and reject Domain layers, Providers, or private package paths\tjson-codec.md\nUTL-LIGHTWEIGHT\tutils\tarchitecture\terror\tUtils is private and owns no durable engine, planner, compiler, Repository, service locator, or dependency container\tInspect package exports and declarations and report public exposure or any forbidden framework machinery\tresult.md\nSCR-OPERATOR\tscripts\tbehavior\terror\tEvery root Script implements a supported operator workflow with declared inputs, outcomes, failures, and proof\tInspect each Script contract and report disposable tasks or missing operator semantics\tbackup.md\nSCR-PUBLIC-DEPS\tscripts\tbehavior\terror\tScripts import only dependency-DAG-authorized public facades, standard libraries, and operator libraries and define no Domain behavior\tResolve imports and inspect branches and report private paths, business decisions, graph definitions, or callable behavior\tupgrade.md\nSCR-TEST-DRIVERS\tscripts\tbehavior\terror\tDisposable setup, fixtures, resets, and scenario drivers live under tests/scripts rather than root Scripts\tClassify every Script by supported operator contract and report evidence-only programs at the root\trestore.md\nTST-SYS-OWNER\ttests\tevidence\terror\tRoot Tests owns cross-layer journeys, environments, harnesses, scenarios, seeds, fixtures, and disposable scripts\tInventory evidence support code and report cross-layer artifacts outside Tests or production semantics inside Tests\tmigration-scenario.md\nTST-COLOCATED\ttests\tevidence\terror\tEvery semantic production submodule owns focused evidence in its local __tests__ directory\tJoin production submodules to focused test directories and report missing owners\tfocused-rule.md\n",
5
5
  layers: frozenRows([
6
6
  {
7
7
  id: 'schema',
@@ -25,8 +25,8 @@ export const domainPolicySource = Object.freeze({
25
25
  required: false,
26
26
  },
27
27
  {
28
- id: 'workflows',
29
- sourcePath: 'workflows/',
28
+ id: 'functions',
29
+ sourcePath: 'functions/',
30
30
  required: false,
31
31
  },
32
32
  {
@@ -40,11 +40,6 @@ export const domainPolicySource = Object.freeze({
40
40
  facade: 'integrations.ts',
41
41
  required: false,
42
42
  },
43
- {
44
- id: 'actions',
45
- sourcePath: 'actions/',
46
- required: false,
47
- },
48
43
  {
49
44
  id: 'routes',
50
45
  sourcePath: 'routes/',
@@ -137,34 +132,40 @@ export const domainPolicySource = Object.freeze({
137
132
  condition: 'Integration values use Domain identities',
138
133
  },
139
134
  {
140
- source: 'workflows',
135
+ source: 'functions',
141
136
  target: 'schema',
142
137
  kind: 'runtime',
143
- condition: 'Workflows use public Domain values and event contracts',
138
+ condition: 'Functions implement authored callable values and use public Domain contracts',
144
139
  },
145
140
  {
146
- source: 'workflows',
141
+ source: 'functions',
147
142
  target: 'rules',
148
143
  kind: 'runtime',
149
- condition: 'Workflows make synchronous decisions',
144
+ condition: 'Functions make synchronous decisions',
150
145
  },
151
146
  {
152
- source: 'workflows',
147
+ source: 'functions',
153
148
  target: 'queries',
154
149
  kind: 'runtime',
155
- condition: 'Workflows observe graph state',
150
+ condition: 'Functions perform reusable graph observations',
156
151
  },
157
152
  {
158
- source: 'workflows',
153
+ source: 'functions',
159
154
  target: 'mutations',
160
155
  kind: 'runtime',
161
- condition: 'Workflows change graph state',
156
+ condition: 'Functions perform named graph changes',
162
157
  },
163
158
  {
164
- source: 'workflows',
159
+ source: 'functions',
165
160
  target: 'integrations',
166
161
  kind: 'runtime',
167
- condition: 'Workflows cross external and remote-Domain boundaries',
162
+ condition: 'Functions cross external and remote-Domain boundaries',
163
+ },
164
+ {
165
+ source: 'functions',
166
+ target: 'utils',
167
+ kind: 'runtime',
168
+ condition: 'Functions use generic execution bindings',
168
169
  },
169
170
  {
170
171
  source: 'migrations',
@@ -184,59 +185,11 @@ export const domainPolicySource = Object.freeze({
184
185
  kind: 'runtime',
185
186
  condition: 'Migration descriptors use a generic dedicated wrapper',
186
187
  },
187
- {
188
- source: 'actions',
189
- target: 'schema',
190
- kind: 'runtime',
191
- condition: 'Actions implement authored callable values',
192
- },
193
- {
194
- source: 'actions',
195
- target: 'rules',
196
- kind: 'runtime',
197
- condition: 'Actions make synchronous decisions',
198
- },
199
- {
200
- source: 'actions',
201
- target: 'queries',
202
- kind: 'runtime',
203
- condition: 'Actions perform one query operation',
204
- },
205
- {
206
- source: 'actions',
207
- target: 'mutations',
208
- kind: 'runtime',
209
- condition: 'Actions perform one mutation operation',
210
- },
211
- {
212
- source: 'actions',
213
- target: 'workflows',
214
- kind: 'runtime',
215
- condition: 'Actions delegate a multi-step journey',
216
- },
217
- {
218
- source: 'actions',
219
- target: 'integrations',
220
- kind: 'runtime',
221
- condition: 'Actions perform one boundary operation',
222
- },
223
- {
224
- source: 'actions',
225
- target: 'utils',
226
- kind: 'runtime',
227
- condition: 'Actions use generic execution bindings',
228
- },
229
- {
230
- source: 'routes',
231
- target: 'actions',
232
- kind: 'runtime',
233
- condition: 'Routes target admitted single-operation recipes',
234
- },
235
188
  {
236
189
  source: 'routes',
237
- target: 'workflows',
190
+ target: 'functions',
238
191
  kind: 'runtime',
239
- condition: 'Routes target admitted multi-step recipes',
192
+ condition: 'Routes target admitted Action and Workflow recipes',
240
193
  },
241
194
  {
242
195
  source: 'providers',
@@ -324,15 +277,9 @@ export const domainPolicySource = Object.freeze({
324
277
  },
325
278
  {
326
279
  source: 'runtime',
327
- target: 'actions',
328
- kind: 'composition',
329
- condition: 'Runtime registers the exact local Action implementations',
330
- },
331
- {
332
- source: 'runtime',
333
- target: 'workflows',
280
+ target: 'functions',
334
281
  kind: 'composition',
335
- condition: 'Runtime registers the exact local Workflow implementations',
282
+ condition: 'Runtime registers the exact local Action and Workflow implementations',
336
283
  },
337
284
  {
338
285
  source: 'runtime',
@@ -454,12 +401,6 @@ export const domainPolicySource = Object.freeze({
454
401
  kind: 'evidence',
455
402
  condition: 'Mutation evidence needs Mutation internals',
456
403
  },
457
- {
458
- source: 'tests',
459
- target: 'workflows',
460
- kind: 'evidence',
461
- condition: 'Recovery evidence needs Workflow internals',
462
- },
463
404
  {
464
405
  source: 'tests',
465
406
  target: 'migrations',
@@ -474,9 +415,9 @@ export const domainPolicySource = Object.freeze({
474
415
  },
475
416
  {
476
417
  source: 'tests',
477
- target: 'actions',
418
+ target: 'functions',
478
419
  kind: 'evidence',
479
- condition: 'Callable evidence needs Action internals',
420
+ condition: 'Callable and recovery evidence needs Function internals',
480
421
  },
481
422
  {
482
423
  source: 'tests',
@@ -629,18 +570,18 @@ export const domainPolicySource = Object.freeze({
629
570
  packageTarget: './mutations/*/index.ts',
630
571
  },
631
572
  {
632
- layer: 'workflows',
573
+ layer: 'functions',
633
574
  kind: 'facade',
634
- specifier: '#workflows',
635
- typescriptTarget: './workflows/index.ts',
636
- packageTarget: './workflows/index.ts',
575
+ specifier: '#functions',
576
+ typescriptTarget: './functions/index.ts',
577
+ packageTarget: './functions/index.ts',
637
578
  },
638
579
  {
639
- layer: 'workflows',
580
+ layer: 'functions',
640
581
  kind: 'submodule',
641
- specifier: '#workflows/*',
642
- typescriptTarget: './workflows/*/index.ts',
643
- packageTarget: './workflows/*/index.ts',
582
+ specifier: '#functions/*',
583
+ typescriptTarget: './functions/*/index.ts',
584
+ packageTarget: './functions/*/index.ts',
644
585
  },
645
586
  {
646
587
  layer: 'migrations',
@@ -670,20 +611,6 @@ export const domainPolicySource = Object.freeze({
670
611
  typescriptTarget: './integrations/*/index.ts',
671
612
  packageTarget: './integrations/*/index.ts',
672
613
  },
673
- {
674
- layer: 'actions',
675
- kind: 'facade',
676
- specifier: '#actions',
677
- typescriptTarget: './actions/index.ts',
678
- packageTarget: './actions/index.ts',
679
- },
680
- {
681
- layer: 'actions',
682
- kind: 'submodule',
683
- specifier: '#actions/*',
684
- typescriptTarget: './actions/*/index.ts',
685
- packageTarget: './actions/*/index.ts',
686
- },
687
614
  {
688
615
  layer: 'routes',
689
616
  kind: 'facade',
@@ -121,15 +121,20 @@ export const domainRuleRequirements = Object.freeze([
121
121
  row('MUT-MULTI-WFL', DATAFLOW),
122
122
  row('MUT-STATE-INITIAL', DATAFLOW),
123
123
  row('MUT-STATE-ATOMIC', DATAFLOW),
124
- row('WFL-MULTISTEP', BEHAVIOR),
125
- row('WFL-STEP-EFFECTS', BEHAVIOR),
126
- row('WFL-STEP-IDS', BEHAVIOR),
127
- row('WFL-NO-NEST', BEHAVIOR),
128
- row('WFL-INT-TYPES', DECLARATION),
129
- row('WFL-ONE-OP-STEP', BEHAVIOR),
130
- row('WFL-STATE-CODEC', BEHAVIOR),
131
- row('WFL-RECOVERY', BEHAVIOR),
132
- row('WFL-XDOM-INT', BEHAVIOR_DEPENDENCY),
124
+ row('FNC-ONE-IMPL', BEHAVIOR),
125
+ row('FNC-ONE-OP', BEHAVIOR),
126
+ row('FNC-OP-KINDS', BEHAVIOR),
127
+ row('FNC-BOUNDARIES', BEHAVIOR_DEPENDENCY),
128
+ row('FNC-BINARY-RESULT', BEHAVIOR_DEPENDENCY),
129
+ row('FNC-MULTISTEP', BEHAVIOR),
130
+ row('FNC-STEP-EFFECTS', BEHAVIOR),
131
+ row('FNC-STEP-IDS', BEHAVIOR),
132
+ row('FNC-NO-NEST', BEHAVIOR),
133
+ row('FNC-INT-TYPES', DECLARATION),
134
+ row('FNC-ONE-OP-STEP', BEHAVIOR),
135
+ row('FNC-STATE-CODEC', BEHAVIOR),
136
+ row('FNC-RECOVERY', BEHAVIOR),
137
+ row('FNC-XDOM-INT', BEHAVIOR_DEPENDENCY),
133
138
  row('MIG-EXACT-REVS', DATAFLOW),
134
139
  row('MIG-APP-DATA', DATAFLOW),
135
140
  row('MIG-DEDICATED-CTX', DATAFLOW),
@@ -140,11 +145,6 @@ export const domainRuleRequirements = Object.freeze([
140
145
  row('INT-NEUTRAL', DECLARATION),
141
146
  row('INT-PURE', DEPENDENCY),
142
147
  row('INT-ABILITY-NAME', STRUCTURE),
143
- row('ACT-ONE-IMPL', BEHAVIOR),
144
- row('ACT-ONE-OP', BEHAVIOR),
145
- row('ACT-OP-KINDS', BEHAVIOR),
146
- row('ACT-BOUNDARIES', BEHAVIOR_DEPENDENCY),
147
- row('ACT-BINARY-RESULT', BEHAVIOR_DEPENDENCY),
148
148
  row('RTE-RECIPE', DECLARATION_FLOW),
149
149
  row('RTE-MAPPING', DATAFLOW),
150
150
  row('RTE-CREDENTIAL', DATAFLOW),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.5.0-beta.97",
3
+ "version": "0.5.0-beta.98",
4
4
  "description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
5
5
  "keywords": [
6
6
  "astrale",
@@ -217,11 +217,11 @@
217
217
  "registry": "https://registry.npmjs.org/"
218
218
  },
219
219
  "dependencies": {
220
- "@astrale-os/kernel-client": "0.6.0-beta.39",
221
- "@astrale-os/kernel-core": "0.9.0-beta.29",
222
- "@astrale-os/kernel-dsl": "0.2.0-beta.22",
223
- "@astrale-os/kernel-protocol": "0.5.0-beta.32",
224
- "@astrale-os/kernel-server": "0.5.0-beta.34",
220
+ "@astrale-os/kernel-client": "0.6.0-beta.40",
221
+ "@astrale-os/kernel-core": "0.9.0-beta.30",
222
+ "@astrale-os/kernel-dsl": "0.2.0-beta.23",
223
+ "@astrale-os/kernel-protocol": "0.5.0-beta.33",
224
+ "@astrale-os/kernel-server": "0.5.0-beta.35",
225
225
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
226
226
  "hono": "^4.13.2",
227
227
  "jose": "^6.2.9",