@telorun/analyzer 0.45.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/alias-resolver.d.ts +45 -0
  2. package/dist/alias-resolver.d.ts.map +1 -1
  3. package/dist/alias-resolver.js +33 -0
  4. package/dist/analyzer.d.ts.map +1 -1
  5. package/dist/analyzer.js +106 -5
  6. package/dist/builtins.d.ts.map +1 -1
  7. package/dist/builtins.js +3 -0
  8. package/dist/extends-resolution.d.ts +19 -2
  9. package/dist/extends-resolution.d.ts.map +1 -1
  10. package/dist/extends-resolution.js +25 -1
  11. package/dist/index.d.ts +5 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +3 -1
  14. package/dist/kernel-globals.d.ts +9 -1
  15. package/dist/kernel-globals.d.ts.map +1 -1
  16. package/dist/kernel-globals.js +24 -1
  17. package/dist/resolve-ref-sentinels.d.ts +13 -1
  18. package/dist/resolve-ref-sentinels.d.ts.map +1 -1
  19. package/dist/resolve-ref-sentinels.js +56 -5
  20. package/dist/validate-cel-context.d.ts.map +1 -1
  21. package/dist/validate-cel-context.js +17 -1
  22. package/dist/validate-observed-state.d.ts +98 -0
  23. package/dist/validate-observed-state.d.ts.map +1 -0
  24. package/dist/validate-observed-state.js +304 -0
  25. package/dist/validate-references.d.ts.map +1 -1
  26. package/dist/validate-references.js +8 -2
  27. package/package.json +2 -2
  28. package/src/alias-resolver.ts +58 -0
  29. package/src/analyzer.ts +126 -4
  30. package/src/builtins.ts +3 -0
  31. package/src/extends-resolution.ts +37 -3
  32. package/src/index.ts +13 -0
  33. package/src/kernel-globals.ts +20 -0
  34. package/src/resolve-ref-sentinels.ts +68 -4
  35. package/src/validate-cel-context.ts +20 -1
  36. package/src/validate-observed-state.ts +354 -0
  37. package/src/validate-references.ts +8 -2
@@ -65,4 +65,49 @@ export declare class AliasResolver {
65
65
  * the root `aliases`.
66
66
  */
67
67
  export declare function scopeResolverForModule(ownModule: string | undefined, rootModules: Set<string>, aliasesByModule: Map<string, AliasResolver>): AliasResolver | undefined;
68
+ /** Per-declaring-module alias tables plus the set of root (consumer-owned)
69
+ * modules. The shape `StaticAnalyzer.analyze` already threads through its
70
+ * passes, and what {@link moduleScopedDefResolver} needs to re-scope. */
71
+ export interface ModuleScopes {
72
+ aliasesByModule: ReadonlyMap<string, {
73
+ resolveKind(kind: string): string | undefined;
74
+ }>;
75
+ rootModules: ReadonlySet<string>;
76
+ }
77
+ /** Minimal view of the definition registry a kind lookup needs. */
78
+ export interface DefinitionLookup {
79
+ resolve(kind: string): unknown;
80
+ }
81
+ /**
82
+ * Resolve a kind to its definition **in the scope that declared it**.
83
+ *
84
+ * An `extends` alias belongs to the file it was written in, not to whoever is
85
+ * reading it: a consumer that imports only a backend (the sanctioned "one import
86
+ * instead of two") has no alias for the abstract's library, so folding an
87
+ * inheritance chain with the consumer's table silently stops at the first hop
88
+ * and yields an un-merged schema. `from` — the definition the kind was read off —
89
+ * carries `metadata.module`, which is the scope to resolve in; a chain crossing
90
+ * several modules re-scopes at every hop.
91
+ *
92
+ * `resolveIn` takes the module explicitly, for the top-level lookup where there
93
+ * is no `from` yet (an exported instance's `kind: Self.X` is written in the
94
+ * exporting library's scope, which the consumer's table cannot resolve either).
95
+ *
96
+ * The runtime counterpart is `resource-definition-controller`, which resolves
97
+ * against the defining module context and stamps the result; keeping both on the
98
+ * same rule is what stops `telo check` and the kernel from disagreeing about
99
+ * which inherited fields a child kind may set.
100
+ */
101
+ export declare function moduleScopedDefResolver<T>(defs: {
102
+ resolve(kind: string): T | undefined;
103
+ }, aliases?: {
104
+ resolveKind(kind: string): string | undefined;
105
+ }, scopes?: ModuleScopes): {
106
+ (kind: string, from?: {
107
+ metadata?: {
108
+ module?: string;
109
+ };
110
+ }): T | undefined;
111
+ in(kind: string, module?: string): T | undefined;
112
+ };
68
113
  //# sourceMappingURL=alias-resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"alias-resolver.d.ts","sourceRoot":"","sources":["../src/alias-resolver.ts"],"names":[],"mappings":"AAAA;gFACgF;AAChF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAChE;;4FAEwF;IACxF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6B;IAE7D;;;;;0EAKsE;IACtE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAO5F;+FAC2F;IAC3F,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAI/D;sFACkF;IAClF,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAIhF;;;;qDAIiD;IACjD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIjD;;;;;;;;iFAQ6E;IAC7E,iBAAiB,CACf,IAAI,EAAE,MAAM,GAEV;QAAE,MAAM,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC9B;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,GACvD;QAAE,MAAM,EAAE,SAAS,CAAA;KAAE;IAoBzB;8EAC0E;IAC1E,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK7C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhC,YAAY,IAAI,MAAM,EAAE;IAIxB;;qEAEiE;IACjE,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE;CAO3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC1C,aAAa,GAAG,SAAS,CAI3B"}
1
+ {"version":3,"file":"alias-resolver.d.ts","sourceRoot":"","sources":["../src/alias-resolver.ts"],"names":[],"mappings":"AAAA;gFACgF;AAChF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAChE;;4FAEwF;IACxF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6B;IAE7D;;;;;0EAKsE;IACtE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAO5F;+FAC2F;IAC3F,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAI/D;sFACkF;IAClF,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAIhF;;;;qDAIiD;IACjD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIjD;;;;;;;;iFAQ6E;IAC7E,iBAAiB,CACf,IAAI,EAAE,MAAM,GAEV;QAAE,MAAM,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC9B;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,GACvD;QAAE,MAAM,EAAE,SAAS,CAAA;KAAE;IAoBzB;8EAC0E;IAC1E,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK7C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhC,YAAY,IAAI,MAAM,EAAE;IAIxB;;qEAEiE;IACjE,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE;CAO3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC1C,aAAa,GAAG,SAAS,CAI3B;AAED;;0EAE0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE;QAAE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IACxF,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,IAAI,EAAE;IAAE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAA;CAAE,EAC9C,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,EAC3D,MAAM,CAAC,EAAE,YAAY,GACpB;IACD,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,CAAC,GAAG,SAAS,CAAC;IACzE,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;CAClD,CAgBA"}
@@ -107,3 +107,36 @@ export function scopeResolverForModule(ownModule, rootModules, aliasesByModule)
107
107
  ? aliasesByModule.get(ownModule)
108
108
  : undefined;
109
109
  }
110
+ /**
111
+ * Resolve a kind to its definition **in the scope that declared it**.
112
+ *
113
+ * An `extends` alias belongs to the file it was written in, not to whoever is
114
+ * reading it: a consumer that imports only a backend (the sanctioned "one import
115
+ * instead of two") has no alias for the abstract's library, so folding an
116
+ * inheritance chain with the consumer's table silently stops at the first hop
117
+ * and yields an un-merged schema. `from` — the definition the kind was read off —
118
+ * carries `metadata.module`, which is the scope to resolve in; a chain crossing
119
+ * several modules re-scopes at every hop.
120
+ *
121
+ * `resolveIn` takes the module explicitly, for the top-level lookup where there
122
+ * is no `from` yet (an exported instance's `kind: Self.X` is written in the
123
+ * exporting library's scope, which the consumer's table cannot resolve either).
124
+ *
125
+ * The runtime counterpart is `resource-definition-controller`, which resolves
126
+ * against the defining module context and stamps the result; keeping both on the
127
+ * same rule is what stops `telo check` and the kernel from disagreeing about
128
+ * which inherited fields a child kind may set.
129
+ */
130
+ export function moduleScopedDefResolver(defs, aliases, scopes) {
131
+ const resolveIn = (kind, module) => {
132
+ const scoped = module && scopes && !scopes.rootModules.has(module)
133
+ ? scopes.aliasesByModule.get(module)
134
+ : undefined;
135
+ return ((scoped ? defs.resolve(scoped.resolveKind(kind) ?? kind) : undefined) ??
136
+ defs.resolve(aliases?.resolveKind(kind) ?? kind) ??
137
+ defs.resolve(kind));
138
+ };
139
+ const resolver = ((kind, from) => resolveIn(kind, from?.metadata?.module));
140
+ resolver.in = resolveIn;
141
+ return resolver;
142
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAsB9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AA8xB/F,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,OAAO,GAAE,qBAA0B;IAI/C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IA07BvB,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IAMvB,SAAS,CACP,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,EAI1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,GACtC,gBAAgB,EAAE;IAmBrB,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,GACzB;QAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAsB5F"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AA6B9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAyyB/F,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,OAAO,GAAE,qBAA0B;IAI/C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IA4hCvB,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IAMvB,SAAS,CACP,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,EAI1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,GACtC,gBAAgB,EAAE;IAyBrB,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,GACzB;QAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAsB5F"}
package/dist/analyzer.js CHANGED
@@ -1,4 +1,4 @@
1
- import { canonicalTypeSchemaId } from "@telorun/sdk";
1
+ import { canonicalTypeSchemaId, OBSERVED_STATE_KEY } from "@telorun/sdk";
2
2
  import { defaultRegistry, isRefSentinel, isTaggedSentinel } from "@telorun/templating";
3
3
  import { AliasResolver, scopeResolverForModule } from "./alias-resolver.js";
4
4
  import { buildCelEnvironment, buildImportInputCelEnvironment, buildTypedCelEnvironment, } from "./cel-environment.js";
@@ -6,6 +6,7 @@ import { DefinitionRegistry } from "./definition-registry.js";
6
6
  import { effectiveAuthorSchema } from "./extends-resolution.js";
7
7
  import { buildDependencyGraph, formatCycle } from "./dependency-graph.js";
8
8
  import { buildKernelGlobalsSchema, mergeKernelGlobalsIntoContext } from "./kernel-globals.js";
9
+ import { buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, } from "./validate-observed-state.js";
9
10
  import { computeSuggestKind } from "./kind-suggest.js";
10
11
  import { visitManifest } from "./manifest-visitor.js";
11
12
  import { isModuleKind } from "./module-kinds.js";
@@ -19,7 +20,7 @@ import { rewriteSyntheticOrigins } from "./rewrite-synthetic-origins.js";
19
20
  import { celTypeSatisfiesJsonSchema, substituteCelFields, validateAgainstSchema, } from "./schema-compat.js";
20
21
  import { collectValueSchemaIssues } from "./validate-value-schema.js";
21
22
  import { DiagnosticSeverity } from "./types.js";
22
- import { extractCelRegionScopes, extractContextsFromSchema, getManifestItem, pathMatchesScope, resolveContextAnnotations, resolveTypeFieldToSchema, } from "./validate-cel-context.js";
23
+ import { extractAccessChains, extractCelRegionScopes, extractContextsFromSchema, getManifestItem, pathMatchesScope, resolveContextAnnotations, resolveTypeFieldToSchema, } from "./validate-cel-context.js";
23
24
  import { buildEvalPaths, evalPathsCover } from "./eval-paths.js";
24
25
  import { validateExtends } from "./validate-extends.js";
25
26
  import { validateLogging } from "./validate-logging.js";
@@ -601,6 +602,16 @@ function errorContextForPath(path, scopes) {
601
602
  }
602
603
  return best?.schema;
603
604
  }
605
+ /** Member-access chains in a CEL expression, or none when it doesn't parse.
606
+ * Best-effort: a syntax error is reported by the engine pass, not here. */
607
+ function celAccessChains(env, expr) {
608
+ try {
609
+ return extractAccessChains(env.parse(expr).ast);
610
+ }
611
+ catch {
612
+ return [];
613
+ }
614
+ }
604
615
  const CEL_PURE_RE = /^\s*\$\{\{[^}]*\}\}\s*$/;
605
616
  const CEL_EXPR_RE = /\$\{\{\s*([^}]+?)\s*\}\}/;
606
617
  /** Recursively walk `data`+`schema` together, type-checking every pure CEL template
@@ -962,7 +973,7 @@ export class StaticAnalyzer {
962
973
  // {kind, name} objects so downstream phases (validation, dependency graph,
963
974
  // kernel controllers) see a uniform shape. Runs after normalize so both
964
975
  // original and inline-extracted manifests have their sentinels resolved.
965
- resolveRefSentinels(allManifests, aliases, aliasesByModule);
976
+ resolveRefSentinels(allManifests, aliases, aliasesByModule, [], defs);
966
977
  // Phase 2.6: register each named `Telo.Type` resource's schema under its
967
978
  // canonical module-scoped id (`telo://<module>/<name>`), validate
968
979
  // `telo://Self|Alias/Type` schema refs resolve to one, then rewrite those
@@ -1100,9 +1111,34 @@ export class StaticAnalyzer {
1100
1111
  }
1101
1112
  }
1102
1113
  }
1114
+ // What each resource reports while running (`status:`), and which resources
1115
+ // some slot can actually start. Both feed the observed-state checks below.
1116
+ // A RESOURCE's kind is written in the module that declares it and is never
1117
+ // canonicalized (unlike a definition's `extends`, normalized at registration
1118
+ // above), so an exported instance's `kind: Self.X` only resolves in its own
1119
+ // library's scope.
1120
+ const moduleScopes = { aliasesByModule, rootModules };
1121
+ const observedState = buildObservedStateIndex(allManifests, defs, aliases, moduleScopes);
1122
+ const reportsObservedState = [...observedState.values()].some((r) => r.status);
1123
+ const runReachable = reportsObservedState
1124
+ ? collectRunReachableNames(allManifests, defs, aliases)
1125
+ : new Set();
1103
1126
  // Build typed kernel globals schema so x-telo-context chain validation
1104
1127
  // recognises variables, secrets, resources, env automatically
1105
- const kernelGlobals = buildKernelGlobalsSchema(allManifests);
1128
+ const kernelGlobals = buildKernelGlobalsSchema(allManifests, observedState);
1129
+ // Fallback context for CEL in a slot with no `x-telo-context` annotation:
1130
+ // everything stays open except the typed `.status` nodes, so unknown-field
1131
+ // checking reaches observed state everywhere without newly rejecting any
1132
+ // read that passes today.
1133
+ const observedStateContext = reportsObservedState
1134
+ ? {
1135
+ type: "object",
1136
+ additionalProperties: true,
1137
+ properties: {
1138
+ resources: buildObservedStateResourcesSchema(observedState, true),
1139
+ },
1140
+ }
1141
+ : null;
1106
1142
  // The module doc (Application/Library) carries the Application-only `ports`
1107
1143
  // namespace; threaded into per-resource CEL typing so `${{ ports.X }}`
1108
1144
  // resolves its nominal brand cross-doc.
@@ -1358,6 +1394,9 @@ export class StaticAnalyzer {
1358
1394
  // `x-telo-step-context` / `x-telo-error-context` scopes. A `!cel` outside
1359
1395
  // every region is read as a literal — the runtime never evaluates it.
1360
1396
  let celEvalPaths = [];
1397
+ // The compile half alone: a field that resolves at startup, where observed
1398
+ // state cannot exist yet.
1399
+ let celCompilePaths = [];
1361
1400
  let celRegionScopes = [];
1362
1401
  let celRuleApplies = false;
1363
1402
  visitManifest(allManifests, defs, {
@@ -1382,10 +1421,15 @@ export class StaticAnalyzer {
1382
1421
  ? buildEvalPaths(capabilityDef.schema)
1383
1422
  : { compile: [], runtime: [] };
1384
1423
  celEvalPaths = [...own.compile, ...own.runtime, ...parent.compile, ...parent.runtime];
1424
+ // A `Telo.Provider`'s fields are implicitly compile-eval — the
1425
+ // capability abstract carries the root annotation — so its reads are
1426
+ // covered here without the provider restating anything.
1427
+ celCompilePaths = [...own.compile, ...parent.compile];
1385
1428
  celRegionScopes = extractCelRegionScopes(ownSchema);
1386
1429
  }
1387
1430
  else {
1388
1431
  celEvalPaths = [];
1432
+ celCompilePaths = [];
1389
1433
  celRegionScopes = [];
1390
1434
  }
1391
1435
  },
@@ -1414,6 +1458,40 @@ export class StaticAnalyzer {
1414
1458
  });
1415
1459
  return;
1416
1460
  }
1461
+ // Observed state exists only while the application runs, so a path
1462
+ // through `.status` is illegal in a field that resolves at startup —
1463
+ // and a resource nothing can start reports nothing, ever. Both are
1464
+ // decided from the expression and the manifest alone.
1465
+ if (reportsObservedState && engineName === "cel" && expr.includes(OBSERVED_STATE_KEY)) {
1466
+ for (const chain of celAccessChains(this.celEnv, expr)) {
1467
+ const read = observedStateRead(chain);
1468
+ if (!read)
1469
+ continue;
1470
+ // An import's exported instance is indexed under `<Alias>.<name>`,
1471
+ // the two-level shape it publishes under, so a cross-module read
1472
+ // is checked exactly like a local one.
1473
+ const reported = observedState.get(read.alias ? `${read.alias}.${read.name}` : read.name);
1474
+ if (celRuleApplies && evalPathsCover(celCompilePaths, path)) {
1475
+ diagnostics.push({
1476
+ severity: DiagnosticSeverity.Error,
1477
+ code: "OBSERVED_STATE_IN_STARTUP_FIELD",
1478
+ source: SOURCE,
1479
+ message: `${m.kind}/${resource.name}: '${path}' is resolved once at startup, so '${chain.join(".")}' does not exist yet — '${read.name}' reports it only while the application is running. Read reported values where the call happens: a step's inputs:, a request's url, a route handler, or a returns: expression.`,
1480
+ data: { resource, filePath, path },
1481
+ });
1482
+ continue;
1483
+ }
1484
+ if (reported && !runReachable.has(read.name)) {
1485
+ diagnostics.push({
1486
+ severity: DiagnosticSeverity.Error,
1487
+ code: "OBSERVED_STATE_NEVER_RUN",
1488
+ source: SOURCE,
1489
+ message: `${m.kind}/${resource.name}: '${read.name}' reports '${read.field ?? OBSERVED_STATE_KEY}' only while it is running, and nothing starts it. Add '!ref ${read.name}' to a targets: list, or invoke it from a step.`,
1490
+ data: { resource, filePath, path },
1491
+ });
1492
+ }
1493
+ }
1494
+ }
1417
1495
  let matchedContext = e.contextSchema ?? celInvocationContext;
1418
1496
  if (celStepContextSchema) {
1419
1497
  const base = matchedContext ?? { type: "object", properties: {}, additionalProperties: true };
@@ -1452,6 +1530,13 @@ export class StaticAnalyzer {
1452
1530
  });
1453
1531
  effectiveContext = mergeKernelGlobalsIntoContext(resolvedContext, kernelGlobals);
1454
1532
  }
1533
+ else if (observedStateContext) {
1534
+ // No `x-telo-context` matched, so nothing was chain-validated here
1535
+ // before. Validate the observed-state segment alone rather than
1536
+ // merging the kernel globals, whose closed `variables` / `ports`
1537
+ // nodes would newly reject reads that pass today.
1538
+ effectiveContext = observedStateContext;
1539
+ }
1455
1540
  const engine = defaultRegistry().get(engineName);
1456
1541
  if (!engine) {
1457
1542
  // No registered engine owns this tag — the expression would go
@@ -1515,6 +1600,22 @@ export class StaticAnalyzer {
1515
1600
  // deliberately skips (behind the step `$ref`), so a missing instance or a
1516
1601
  // kind-instead-of-instance ref there is caught statically, not at runtime.
1517
1602
  diagnostics.push(...validateStepInvokeReferences(allManifests, defs, aliases));
1603
+ // `required:` inside a `status:` block — reported here rather than by the
1604
+ // AJV shape, which could only say "must NOT be valid" without naming the
1605
+ // rule or the fix.
1606
+ for (const issue of validateObservedStateDeclarations(allManifests)) {
1607
+ diagnostics.push({
1608
+ severity: DiagnosticSeverity.Error,
1609
+ code: "OBSERVED_STATE_REQUIRED_FORBIDDEN",
1610
+ source: SOURCE,
1611
+ message: issue.message,
1612
+ data: {
1613
+ resource: { kind: issue.kind, name: issue.name },
1614
+ filePath: issue.filePath,
1615
+ path: "status.required",
1616
+ },
1617
+ });
1618
+ }
1518
1619
  // Validate `extends` fields and flag legacy `capability: <UserAbstract>` overload.
1519
1620
  diagnostics.push(...validateExtends(allManifests, defs, aliases));
1520
1621
  diagnostics.push(...validateBaseMapping(allManifests, defs, aliases));
@@ -1541,7 +1642,7 @@ export class StaticAnalyzer {
1541
1642
  // Resolve !ref sentinels after normalize so both the original and
1542
1643
  // inline-extracted manifests get their refs canonicalized to
1543
1644
  // {kind, name} for the kernel that consumes this output.
1544
- resolveRefSentinels(normalized, ctx.aliases, ctx.aliasesByModule, crossModuleTargets ?? []);
1645
+ resolveRefSentinels(normalized, ctx.aliases, ctx.aliasesByModule, crossModuleTargets ?? [], ctx.definitions);
1545
1646
  // Canonicalize import-scoped schema `$ref`s (`telo://Self|Alias/Type`) so the
1546
1647
  // kernel that executes this output compiles inputs/outputs against the same
1547
1648
  // ids the type controllers register their schemas under.
@@ -1 +1 @@
1
- {"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AA2GvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EA6nB/C,CAAC"}
1
+ {"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AA4GvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EA+nB/C,CAAC"}
package/dist/builtins.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { OBSERVED_STATE_SCHEMA } from "./validate-observed-state.js";
1
2
  /** Descriptive provenance a module declares about itself, shared by
2
3
  * `Telo.Application` and `Telo.Library`.
3
4
  *
@@ -177,6 +178,7 @@ export const KERNEL_BUILTINS = [
177
178
  },
178
179
  capability: { type: "string" },
179
180
  schema: { type: "object", additionalProperties: true },
181
+ status: OBSERVED_STATE_SCHEMA,
180
182
  },
181
183
  required: ["metadata"],
182
184
  // Telo.Abstract is an extension point by design — it must accept forward-compatible
@@ -205,6 +207,7 @@ export const KERNEL_BUILTINS = [
205
207
  type: "object",
206
208
  additionalProperties: true,
207
209
  properties: {
210
+ status: OBSERVED_STATE_SCHEMA,
208
211
  resources: {
209
212
  type: "array",
210
213
  items: {
@@ -1,7 +1,13 @@
1
1
  import type { ResourceDefinition } from "@telorun/sdk";
2
2
  /** Resolves a kind string (canonical or alias form, depending on the caller's
3
- * registry) to its `Telo.Definition` / `Telo.Abstract`, or undefined. */
4
- export type DefResolver = (kind: string) => ResourceDefinition | undefined;
3
+ * registry) to its `Telo.Definition` / `Telo.Abstract`, or undefined.
4
+ *
5
+ * `from` is the definition the kind was read off. An `extends` alias belongs to
6
+ * the file that DECLARES the definition, not to whoever is reading it, so a
7
+ * resolver that walks an inheritance chain across module boundaries must
8
+ * re-scope at each hop — `from.metadata.module` is what it scopes to. Resolvers
9
+ * that operate in a single scope ignore the parameter. */
10
+ export type DefResolver = (kind: string, from?: ResourceDefinition) => ResourceDefinition | undefined;
5
11
  /** The definition a given definition directly `extends`, or undefined when it
6
12
  * extends nothing / the target can't be resolved. */
7
13
  export declare function resolveParent(def: ResourceDefinition | undefined, resolve: DefResolver): ResourceDefinition | undefined;
@@ -30,4 +36,15 @@ export declare function inheritedCapability(def: ResourceDefinition | undefined,
30
36
  * `mergeTypeSchemas` that `Type.JsonSchema.extends` uses.
31
37
  * - no `extends` → the own schema unchanged. */
32
38
  export declare function effectiveAuthorSchema(def: ResourceDefinition | undefined, resolve: DefResolver): Record<string, any>;
39
+ /** The observed state a kind reports (`status:`), folded through `extends`:
40
+ * - with `base:` present → the **parent's** effective status unchanged; the
41
+ * child delegates to the parent's controller and *is* a parent instance, so
42
+ * it publishes exactly what the parent publishes.
43
+ * - without `base:` but with `extends` → `merge(parent-effective, own)`, so a
44
+ * contract can mandate what its implementations report and an implementation
45
+ * can add to it.
46
+ * - no `extends` → the own block unchanged.
47
+ * Undefined when nothing in the chain declares one — the signal that the kind
48
+ * has not opted into typed `.status` reads. */
49
+ export declare function effectiveStatusSchema(def: ResourceDefinition | undefined, resolve: DefResolver): Record<string, any> | undefined;
33
50
  //# sourceMappingURL=extends-resolution.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;0EAC0E;AAC1E,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;AAqB3E;sDACsD;AACtD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAIhC;AAED;6EAC6E;AAC7E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,EAAE,CAUtB;AAED;iFACiF;AACjF,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAUvF;AAED;;mFAEmF;AACnF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAMhC;AAED;;sCAEsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAGT;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;iDAMiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOrB"}
1
+ {"version":3,"file":"extends-resolution.d.ts","sourceRoot":"","sources":["../src/extends-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD;;;;;;;2DAO2D;AAC3D,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,kBAAkB,KACtB,kBAAkB,GAAG,SAAS,CAAC;AAsBpC;sDACsD;AACtD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAIhC;AAED;6EAC6E;AAC7E,wBAAgB,aAAa,CAC3B,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,EAAE,CAUtB;AAED;iFACiF;AACjF,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAUvF;AAED;;mFAEmF;AACnF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,kBAAkB,GAAG,SAAS,CAMhC;AAED;;sCAEsC;AACtC,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,OAAO,CAGT;AAED;2EAC2E;AAC3E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;;iDAMiD;AACjD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAOrB;AAED;;;;;;;;;gDASgD;AAChD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EACnC,OAAO,EAAE,WAAW,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CASjC"}
@@ -6,7 +6,7 @@ export function resolveParent(def, resolve) {
6
6
  const ext = body(def).extends;
7
7
  if (typeof ext !== "string" || ext.length === 0)
8
8
  return undefined;
9
- return resolve(ext);
9
+ return resolve(ext, def);
10
10
  }
11
11
  /** The `extends` ancestor chain, nearest-first, excluding `def` itself.
12
12
  * Cycle-guarded so a malformed self/mutual `extends` can't loop forever. */
@@ -80,3 +80,27 @@ export function effectiveAuthorSchema(def, resolve) {
80
80
  const parentSchema = effectiveAuthorSchema(parent, resolve);
81
81
  return mergeTypeSchemas([parentSchema, own]);
82
82
  }
83
+ /** The observed state a kind reports (`status:`), folded through `extends`:
84
+ * - with `base:` present → the **parent's** effective status unchanged; the
85
+ * child delegates to the parent's controller and *is* a parent instance, so
86
+ * it publishes exactly what the parent publishes.
87
+ * - without `base:` but with `extends` → `merge(parent-effective, own)`, so a
88
+ * contract can mandate what its implementations report and an implementation
89
+ * can add to it.
90
+ * - no `extends` → the own block unchanged.
91
+ * Undefined when nothing in the chain declares one — the signal that the kind
92
+ * has not opted into typed `.status` reads. */
93
+ export function effectiveStatusSchema(def, resolve) {
94
+ const own = body(def).status;
95
+ const parent = resolveParent(def, resolve);
96
+ if (!parent)
97
+ return own;
98
+ const parentStatus = effectiveStatusSchema(parent, resolve);
99
+ if (body(def).base)
100
+ return parentStatus;
101
+ if (!parentStatus)
102
+ return own;
103
+ if (!own)
104
+ return parentStatus;
105
+ return mergeTypeSchemas([parentStatus, own]);
106
+ }
package/dist/index.d.ts CHANGED
@@ -5,7 +5,11 @@ export { importResolutionDiagnostics } from "./import-resolution-diagnostics.js"
5
5
  export type { GraphLoadError, ImportEdge, LoadedFile, LoadedGraph, LoadedModule, ParseError, } from "./loaded-types.js";
6
6
  export { flattenForAnalyzer, flattenLoadedModule, forwardReExportManifests, parseExportEntry, reExportSpecsFromExports, resolveExportedKinds, selectModuleManifestsForAnalysis, stampExportedKinds, stampReExportedKinds, type ParsedExportEntry, type ReExportSpec, } from "./flatten-for-analyzer.js";
7
7
  export { buildEvalPaths, evalPathCovers } from "./eval-paths.js";
8
- export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
8
+ export { applyObservedStateNode, buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, OBSERVED_STATE_SCHEMA, } from "./validate-observed-state.js";
9
+ export type { AnalyzedResource, ObservedStateRead } from "./validate-observed-state.js";
10
+ export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolver.js";
11
+ export type { ModuleScopes } from "./alias-resolver.js";
12
+ export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
9
13
  export type { DefResolver } from "./extends-resolution.js";
10
14
  export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
11
15
  export type { RedactionSegment } from "./redaction-path.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,YAAY,EACR,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACH,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,gCAAgC,EAChC,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,qBAAqB,EACrB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,GACd,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC5F,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EACR,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,YAAY,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EACH,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,GACnB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACzE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC/E,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC3E,YAAY,EACR,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,aAAa,EACb,KAAK,EACR,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,7 +3,9 @@ export { StaticAnalyzer } from "./analyzer.js";
3
3
  export { importResolutionDiagnostics } from "./import-resolution-diagnostics.js";
4
4
  export { flattenForAnalyzer, flattenLoadedModule, forwardReExportManifests, parseExportEntry, reExportSpecsFromExports, resolveExportedKinds, selectModuleManifestsForAnalysis, stampExportedKinds, stampReExportedKinds, } from "./flatten-for-analyzer.js";
5
5
  export { buildEvalPaths, evalPathCovers } from "./eval-paths.js";
6
- export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
6
+ export { applyObservedStateNode, buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, OBSERVED_STATE_SCHEMA, } from "./validate-observed-state.js";
7
+ export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolver.js";
8
+ export { ancestorChain, controllerBearingAncestor, effectiveAuthorSchema, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, resolveParent, } from "./extends-resolution.js";
7
9
  export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
8
10
  export { buildReferenceFieldMap, isRefEntry, isScopeEntry } from "./reference-field-map.js";
9
11
  export { visitManifest } from "./manifest-visitor.js";
@@ -24,7 +24,15 @@ export declare const KERNEL_GLOBAL_NAMES: readonly ["variables", "secrets", "res
24
24
  * the manifest list to a single library's file.
25
25
  * - `resources`: enumerates all non-system resource names
26
26
  */
27
- export declare function buildKernelGlobalsSchema(manifests: ResourceManifest[]): Record<string, any>;
27
+ export declare function buildKernelGlobalsSchema(manifests: ResourceManifest[],
28
+ /** Every resource a CEL read can name, including scope-declared ones (see
29
+ * `buildObservedStateIndex`). Kinds that declare a `status:` get a typed,
30
+ * closed `status` node; every other resource node stays open, so no flat read
31
+ * that passes today can start failing. */
32
+ resources?: ReadonlyMap<string, {
33
+ kind: string;
34
+ status?: Record<string, any>;
35
+ }>): Record<string, any>;
28
36
  /**
29
37
  * Merge kernel globals into an `x-telo-context` schema so chain-access
30
38
  * validation recognises `variables`, `secrets`, `resources`, `ports`
@@ -1 +1 @@
1
- {"version":3,"file":"kernel-globals.d.ts","sourceRoot":"","sources":["../src/kernel-globals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,yDAA0D,CAAC;AAS3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiCrB;AA4CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB"}
1
+ {"version":3,"file":"kernel-globals.d.ts","sourceRoot":"","sources":["../src/kernel-globals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,yDAA0D,CAAC;AAS3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE;AAC7B;;;2CAG2C;AAC3C,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,GAC9E,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA+CrB;AA4CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB"}
@@ -1,4 +1,5 @@
1
1
  import { residualEntrySchemaMap } from "./residual-schema.js";
2
+ import { applyObservedStateNode } from "./validate-observed-state.js";
2
3
  /**
3
4
  * Kernel global names available in every CEL evaluation context at runtime.
4
5
  * Both `buildKernelGlobalsSchema` (chain-access validation) and
@@ -30,7 +31,12 @@ const SYSTEM_KINDS = new Set([
30
31
  * the manifest list to a single library's file.
31
32
  * - `resources`: enumerates all non-system resource names
32
33
  */
33
- export function buildKernelGlobalsSchema(manifests) {
34
+ export function buildKernelGlobalsSchema(manifests,
35
+ /** Every resource a CEL read can name, including scope-declared ones (see
36
+ * `buildObservedStateIndex`). Kinds that declare a `status:` get a typed,
37
+ * closed `status` node; every other resource node stays open, so no flat read
38
+ * that passes today can start failing. */
39
+ resources) {
34
40
  const moduleManifest = manifests.find((m) => m.kind === "Telo.Application") ??
35
41
  manifests.find((m) => m.kind === "Telo.Library");
36
42
  const resourceProps = {};
@@ -44,6 +50,23 @@ export function buildKernelGlobalsSchema(manifests) {
44
50
  resourceProps[name] = { type: "object", additionalProperties: true };
45
51
  }
46
52
  }
53
+ // Scope-declared resources (a `Run.Sequence`'s `with:`) publish like any other
54
+ // now, so their names resolve too — inside the scope's regions, which is where
55
+ // the only expressions that can name them live.
56
+ for (const [key, entry] of resources ?? []) {
57
+ if (key.includes("."))
58
+ continue;
59
+ resourceProps[key] ??= { type: "object", additionalProperties: true };
60
+ if (entry.status)
61
+ applyObservedStateNode(resourceProps, key, entry.status);
62
+ }
63
+ // Imports' exported instances publish two levels deep (`resources.<Alias>.<name>`);
64
+ // the alias node stays open so its other keys keep resolving.
65
+ for (const [key, entry] of resources ?? []) {
66
+ if (!key.includes(".") || !entry.status)
67
+ continue;
68
+ applyObservedStateNode(resourceProps, key, entry.status);
69
+ }
47
70
  return {
48
71
  type: "object",
49
72
  properties: {
@@ -1,5 +1,13 @@
1
1
  import type { ResourceManifest } from "@telorun/sdk";
2
2
  import type { AliasResolver } from "./alias-resolver.js";
3
+ import { type ReferenceFieldMap } from "./reference-field-map.js";
4
+ /** The slice of the definition registry this pass needs: a kind's field map, from
5
+ * which the `x-telo-scope` slots are read. */
6
+ export interface ScopeFieldMapSource {
7
+ getFieldMapForKind(kind: string, aliases?: {
8
+ resolveKind(k: string): string | undefined;
9
+ }): ReferenceFieldMap | undefined;
10
+ }
3
11
  /**
4
12
  * Rewrites every `!ref <name>` sentinel in each non-system resource's value tree
5
13
  * to `{kind, name}` (local) or `{kind, name, alias}` (cross-module), in place.
@@ -36,5 +44,9 @@ import type { AliasResolver } from "./alias-resolver.js";
36
44
  * `metadata.module` that isn't a root module) are resolution TARGETS only — they are not
37
45
  * re-walked as sources here, since their own ref slots belong to their own module scope.
38
46
  */
39
- export declare function resolveRefSentinels(resources: ResourceManifest[], aliases?: AliasResolver, aliasesByModule?: Map<string, AliasResolver>, crossModuleTargets?: ResourceManifest[]): void;
47
+ export declare function resolveRefSentinels(resources: ResourceManifest[], aliases?: AliasResolver, aliasesByModule?: Map<string, AliasResolver>, crossModuleTargets?: ResourceManifest[],
48
+ /** Supplies each kind's `x-telo-scope` slots. Without it a scoped name cannot be
49
+ * told from a module-level one, and a shadowed `!ref` resolves to the resource
50
+ * it shadows — so both call sites pass it. */
51
+ defs?: ScopeFieldMapSource): void;
40
52
  //# sourceMappingURL=resolve-ref-sentinels.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-ref-sentinels.d.ts","sourceRoot":"","sources":["../src/resolve-ref-sentinels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAK5C,kBAAkB,GAAE,gBAAgB,EAAO,GAC1C,IAAI,CAgFN"}
1
+ {"version":3,"file":"resolve-ref-sentinels.d.ts","sourceRoot":"","sources":["../src/resolve-ref-sentinels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAGlC;+CAC+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,CAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,GACvD,iBAAiB,GAAG,SAAS,CAAC;CAClC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAK5C,kBAAkB,GAAE,gBAAgB,EAAO;AAC3C;;+CAE+C;AAC/C,IAAI,CAAC,EAAE,mBAAmB,GACzB,IAAI,CA8HN"}