@telorun/analyzer 0.58.0 → 0.59.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.
package/dist/index.d.ts CHANGED
@@ -13,8 +13,8 @@ export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolve
13
13
  export type { ModuleScopes } from "./alias-resolver.js";
14
14
  export { ancestorChain, contractDeclarer, controllerBearingAncestor, effectiveAuthorSchema, effectiveContractField, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, mappingFieldFor, needsContractMapping, resolveParent, } from "./extends-resolution.js";
15
15
  export type { ContractDirection, DefResolver } from "./extends-resolution.js";
16
- export { defaultBearingPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withLiveValuesSkipped, } from "./invocation-contract.js";
17
- export type { ContractOrigin, ContractScope, ResolvedContract } from "./invocation-contract.js";
16
+ export { defaultBearingPaths, declaredScalarPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withLiveValuesSkipped, } from "./invocation-contract.js";
17
+ export type { ContractOrigin, ContractScope, DeclaredScalarForm, DeclaredScalarPath, ResolvedContract, } from "./invocation-contract.js";
18
18
  export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
19
19
  export type { RedactionSegment } from "./redaction-path.js";
20
20
  export { buildCallGraph, projectToPairs, resourceId } from "./call-graph.js";
@@ -37,7 +37,7 @@ export { validateDynamicSelectors, validateRefSlotDeclarations } from "./validat
37
37
  export type { RefSlotIssue } from "./validate-ref-slots.js";
38
38
  export { validateValueTypeSlots } from "./validate-value-type-slots.js";
39
39
  export type { ValueTypeSlotIssue } from "./validate-value-type-slots.js";
40
- export { checkSchemaCompatibility } from "./schema-compat.js";
40
+ export { checkSchemaCompatibility, selectUnionBranch } from "./schema-compat.js";
41
41
  export type { CompatibilityResult } from "./schema-compat.js";
42
42
  export { visitManifest } from "./manifest-visitor.js";
43
43
  export type { CelSiteEvent, ManifestVisitor, RefSiteEvent, ResourceEnterEvent, ResourceExitEvent, ScopeBoundaryEvent, SchemaFromSiteEvent, VisitOptions, } from "./manifest-visitor.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ export { BINDINGS_ANNOTATION, bindingContextProperties, bindingDependencies, fin
7
7
  export { applyObservedStateNode, buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, OBSERVED_STATE_SCHEMA, } from "./validate-observed-state.js";
8
8
  export { moduleScopedDefResolver, scopeResolverForModule } from "./alias-resolver.js";
9
9
  export { ancestorChain, contractDeclarer, controllerBearingAncestor, effectiveAuthorSchema, effectiveContractField, effectiveStatusSchema, hasOwnControllerOrTemplate, inheritedCapability, isInheritedDelegation, mappingFieldFor, needsContractMapping, resolveParent, } from "./extends-resolution.js";
10
- export { defaultBearingPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withLiveValuesSkipped, } from "./invocation-contract.js";
10
+ export { defaultBearingPaths, declaredScalarPaths, PERMISSIVE_CONTRACT, resolveContract, resolveContractSchema, withLiveValuesSkipped, } from "./invocation-contract.js";
11
11
  export { hasIntermediateWildcard, parseRedactionPath, RedactionPathError, } from "./redaction-path.js";
12
12
  export { buildCallGraph, projectToPairs, resourceId } from "./call-graph.js";
13
13
  export { buildReferenceFieldMap, isRefEntry, isScopeEntry } from "./reference-field-map.js";
@@ -19,7 +19,7 @@ export { deriveLibraryExportRequirements, projectZoneRequirements, runZoneAnalys
19
19
  export { validateZoneSlotDeclarations } from "./validate-zone-slots.js";
20
20
  export { validateDynamicSelectors, validateRefSlotDeclarations } from "./validate-ref-slots.js";
21
21
  export { validateValueTypeSlots } from "./validate-value-type-slots.js";
22
- export { checkSchemaCompatibility } from "./schema-compat.js";
22
+ export { checkSchemaCompatibility, selectUnionBranch } from "./schema-compat.js";
23
23
  export { visitManifest } from "./manifest-visitor.js";
24
24
  export { Loader } from "./manifest-loader.js";
25
25
  export { isModuleKind, MODULE_KINDS } from "./module-kinds.js";
@@ -105,4 +105,41 @@ export declare function defaultBearingPaths(schema: Record<string, any>,
105
105
  * declares its defaults behind the reference, and a walk that cannot follow
106
106
  * it would report none, leaving the caller's data shared where a fill lands. */
107
107
  resolveRef?: (ref: string) => Record<string, any> | undefined): string[][];
108
+ /** The scalar form a declared node's value takes at runtime. `int64` and
109
+ * `double` are the two JSON scalars whose runtime representation is NOT decided
110
+ * by the value that arrives: a CEL integer is a BigInt and a CEL double a JS
111
+ * number, and both are `typeof "number" | "bigint"` away from what a declaration
112
+ * says they are. Everything else — string, boolean, object, array, and every
113
+ * `instance` value type — is already its own representation, so it is not
114
+ * listed and never rewritten. */
115
+ export type DeclaredScalarForm = "int64" | "double";
116
+ export interface DeclaredScalarPath {
117
+ readonly path: string[];
118
+ readonly form: DeclaredScalarForm;
119
+ }
120
+ /** Every path in `schema` whose declared type fixes a scalar representation —
121
+ * the leaves a value must carry in that form for the contract to be TRUE, not
122
+ * merely to pass.
123
+ *
124
+ * A declared shape says what the value IS, the same service a JSON Schema gives
125
+ * an HTTP response serializer. Telo's CEL layer takes it literally:
126
+ * `jsonSchemaToCelType` maps `integer` to CEL `int` and `number` to `double`,
127
+ * and a CEL int IS a BigInt — so a controller handing back a plain JS number at
128
+ * an `integer` slot makes the declaration a lie that surfaces nowhere until an
129
+ * expression composes it, as `result.n + 1` type-checking statically and then
130
+ * dying at dispatch with `no such overload: dyn<double> + int`.
131
+ *
132
+ * A VALUE TYPE is read through the same rule rather than beside it: a `json`
133
+ * representation refines a JSON type and contributes its `base` (so
134
+ * `Telo.TcpPort` is an `int64` slot), while an `instance` representation
135
+ * REPLACES the JSON layer — a byte buffer and a stream handle are already their
136
+ * own representation, nothing converts to them, and the walk stops there rather
137
+ * than descending into a value that is not a plain container.
138
+ *
139
+ * Bounded by the schema's declarations rather than by the size of the payload,
140
+ * exactly as {@link defaultBearingPaths} is: a contract declaring no such
141
+ * scalar walks nothing at dispatch. A union counts when it names exactly one of
142
+ * the two — `["integer", "null"]` is still the integer branch, while
143
+ * `["integer", "number"]` fixes nothing and is left alone. */
144
+ export declare function declaredScalarPaths(schema: Record<string, any>, resolveRef?: (ref: string) => Record<string, any> | undefined): DeclaredScalarPath[];
108
145
  //# sourceMappingURL=invocation-contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"invocation-contract.d.ts","sourceRoot":"","sources":["../src/invocation-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,WAAW,EAEjB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC;;;;;;;;;;;;GAYG;AAEH;;oCAEoC;AACpC,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB;gFAC4E;IAC5E,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B;;kEAE8D;IAC9D,iBAAiB,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CAC9E;AAED;;uCAEuC;AACvC,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAGnD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,gBAAgB,GAAG,SAAS,CAa9B;AAED;;mDAEmD;AACnD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;;;6CAI6C;AAC7C,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAoFD;;;;;gEAKgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;iFAEiF;AACjF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,EAAE,EAAE,CA+BZ"}
1
+ {"version":3,"file":"invocation-contract.d.ts","sourceRoot":"","sources":["../src/invocation-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,kBAAkB,EAAe,MAAM,cAAc,CAAC;AAChF,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,WAAW,EAEjB,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC;;;;;;;;;;;;GAYG;AAEH;;oCAEoC;AACpC,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB;gFAC4E;IAC5E,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B;;kEAE8D;IAC9D,iBAAiB,EAAE,WAAW,CAAC;IAC/B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CAC9E;AAED;;uCAEuC;AACvC,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAGnD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,gBAAgB,GAAG,SAAS,CAa9B;AAED;;mDAEmD;AACnD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACzC,UAAU,EAAE,kBAAkB,GAAG,SAAS,EAC1C,KAAK,EAAE,aAAa,GACnB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;;;6CAI6C;AAC7C,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAErB;AAoFD;;;;;gEAKgE;AAChE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;AAC3B;;iFAEiF;AACjF,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,MAAM,EAAE,EAAE,CA+BZ;AAED;;;;;;kCAMkC;AAClC,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEpD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;+DAuB+D;AAC/D,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAC5D,kBAAkB,EAAE,CAoCtB"}
@@ -1,4 +1,4 @@
1
- import { isLiveSlot } from "@telorun/sdk";
1
+ import { isLiveSlot, valueTypeOf } from "@telorun/sdk";
2
2
  import { contractDeclarer, effectiveContractField, } from "./extends-resolution.js";
3
3
  import { resolveTypeFieldToSchema } from "./validate-cel-context.js";
4
4
  /** The fallback for a target that declares no contract: anything goes. Not
@@ -203,3 +203,83 @@ resolveRef) {
203
203
  walk(schema, [], []);
204
204
  return out;
205
205
  }
206
+ /** Every path in `schema` whose declared type fixes a scalar representation —
207
+ * the leaves a value must carry in that form for the contract to be TRUE, not
208
+ * merely to pass.
209
+ *
210
+ * A declared shape says what the value IS, the same service a JSON Schema gives
211
+ * an HTTP response serializer. Telo's CEL layer takes it literally:
212
+ * `jsonSchemaToCelType` maps `integer` to CEL `int` and `number` to `double`,
213
+ * and a CEL int IS a BigInt — so a controller handing back a plain JS number at
214
+ * an `integer` slot makes the declaration a lie that surfaces nowhere until an
215
+ * expression composes it, as `result.n + 1` type-checking statically and then
216
+ * dying at dispatch with `no such overload: dyn<double> + int`.
217
+ *
218
+ * A VALUE TYPE is read through the same rule rather than beside it: a `json`
219
+ * representation refines a JSON type and contributes its `base` (so
220
+ * `Telo.TcpPort` is an `int64` slot), while an `instance` representation
221
+ * REPLACES the JSON layer — a byte buffer and a stream handle are already their
222
+ * own representation, nothing converts to them, and the walk stops there rather
223
+ * than descending into a value that is not a plain container.
224
+ *
225
+ * Bounded by the schema's declarations rather than by the size of the payload,
226
+ * exactly as {@link defaultBearingPaths} is: a contract declaring no such
227
+ * scalar walks nothing at dispatch. A union counts when it names exactly one of
228
+ * the two — `["integer", "null"]` is still the integer branch, while
229
+ * `["integer", "number"]` fixes nothing and is left alone. */
230
+ export function declaredScalarPaths(schema, resolveRef) {
231
+ const out = [];
232
+ const walk = (node, path, chain) => {
233
+ if (!node || typeof node !== "object")
234
+ return;
235
+ let s = node;
236
+ if (chain.includes(s))
237
+ return;
238
+ if (resolveRef && typeof s.$ref === "string") {
239
+ const target = resolveRef(s.$ref);
240
+ if (!target || chain.includes(target))
241
+ return;
242
+ s = { ...target, ...s, $ref: undefined };
243
+ }
244
+ const here = [...chain, node];
245
+ const entry = valueTypeOf(s);
246
+ // An `instance` representation replaces the JSON layer: it is its own
247
+ // representation, so there is nothing to normalize to and nothing below it
248
+ // that is a plain container to walk.
249
+ if (entry && entry.representation === "instance")
250
+ return;
251
+ const form = scalarFormOf(entry && entry.base !== undefined ? entry.base : s.type);
252
+ if (form && path.length > 0)
253
+ out.push({ path, form });
254
+ const properties = s.properties;
255
+ if (properties) {
256
+ for (const [key, child] of Object.entries(properties))
257
+ walk(child, [...path, key], here);
258
+ }
259
+ for (const branch of ["allOf", "anyOf", "oneOf"]) {
260
+ const list = s[branch];
261
+ if (Array.isArray(list))
262
+ for (const child of list)
263
+ walk(child, path, here);
264
+ }
265
+ if (s.items)
266
+ walk(s.items, [...path, "[]"], here);
267
+ };
268
+ walk(schema, [], []);
269
+ return out;
270
+ }
271
+ function scalarFormOf(declared) {
272
+ if (declared === "integer")
273
+ return "int64";
274
+ if (declared === "number")
275
+ return "double";
276
+ if (!Array.isArray(declared))
277
+ return undefined;
278
+ const integer = declared.includes("integer");
279
+ const number = declared.includes("number");
280
+ // A union naming both fixes nothing — either representation satisfies it, so
281
+ // rewriting one into the other would be a choice the declaration never made.
282
+ if (integer === number)
283
+ return undefined;
284
+ return integer ? "int64" : "double";
285
+ }
@@ -78,6 +78,24 @@ export declare function celTypeSatisfiesJsonSchema(celType: string, schema: Reco
78
78
  export declare function celPlaceholderForSchema(rawSchema: Record<string, any>): unknown;
79
79
  /** Resolve a `$ref` (only `#/$defs/...` form) against the root schema. */
80
80
  export declare function resolveRef(schema: Record<string, any>, root: Record<string, any>): Record<string, any>;
81
+ /** Collect property schemas from top-level `properties` and all `oneOf`/`anyOf` sub-schemas. */
82
+ /**
83
+ * The `oneOf` / `anyOf` branch a value is written against, when exactly one fits.
84
+ *
85
+ * A union carries no `type` / `properties` / `items` of its own, so a walker that
86
+ * ignores it descends with an empty schema and hands every CEL leaf underneath a
87
+ * `null` placeholder — which then fails every branch and reports a pile of
88
+ * violations against a value that is perfectly valid. Picking the branch first
89
+ * is what lets the leaves be typed.
90
+ *
91
+ * Selection is structural and conservative: a branch must agree with the data's
92
+ * kind, and for an object every `required` key must be present (which is what
93
+ * separates a `{type, text}` part from a `{type, data, mediaType}` one). If that
94
+ * leaves anything other than exactly one branch, the union is returned unchanged
95
+ * — an ambiguous union is one the analyzer should not resolve on the author's
96
+ * behalf.
97
+ */
98
+ export declare function selectUnionBranch(schema: Record<string, any>, data: unknown, root: Record<string, any>): Record<string, any>;
81
99
  export declare function collectProperties(schema: Record<string, any>): Record<string, any>;
82
100
  /** Deep-clone `data`, replacing every pure CEL template string (`${{ expr }}`) with a
83
101
  * schema-appropriate placeholder so AJV can validate non-CEL fields without false positives. */
@@ -1 +1 @@
1
- {"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema-compat.d.ts","sourceRoot":"","sources":["../src/schema-compat.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,16 @@ export function createAjv() {
27
27
  }
28
28
  const ajv = createAjv();
29
29
  const compiledSchemaValidators = new WeakMap();
30
+ /** The alternatives a union node declares, or undefined when it is not one.
31
+ * `anyOf` and `oneOf` are one question here — which branches could accept this
32
+ * value — and their difference (exactly-one vs at-least-one) is a validation
33
+ * rule, not a compatibility one. */
34
+ function unionBranches(schema) {
35
+ const branches = schema.anyOf ?? schema.oneOf;
36
+ if (!Array.isArray(branches) || branches.length === 0)
37
+ return undefined;
38
+ return branches.filter((b) => b && typeof b === "object");
39
+ }
30
40
  /**
31
41
  * Conservative structural JSON Schema compatibility check — is a value shaped
32
42
  * like `source` acceptable where `target` is declared?
@@ -80,6 +90,37 @@ function compare(rawSource, rawTarget, path, issues, resolveRef, seen) {
80
90
  }
81
91
  const source = deref(rawSource, resolveRef);
82
92
  const target = deref(rawTarget, resolveRef);
93
+ // A union is ALTERNATIVES, so it is compared by distributing over branches on
94
+ // both sides: a definite conflict is one where no source-branch/target-branch
95
+ // pair agrees. Returning silently the moment either side was a union — which
96
+ // is what this did — switched the whole comparison off for any slot that
97
+ // accepts more than one shape, and those are exactly the slots where a value
98
+ // type carries the only information distinguishing the branches.
99
+ //
100
+ // `allOf` is a conjunction rather than a choice, so it keeps the old posture:
101
+ // it says too little to judge and stays compatible.
102
+ if (source.allOf || target.allOf)
103
+ return;
104
+ const sourceBranches = unionBranches(source);
105
+ const targetBranches = unionBranches(target);
106
+ if (sourceBranches || targetBranches) {
107
+ const lefts = sourceBranches ?? [source];
108
+ const rights = targetBranches ?? [target];
109
+ const reasons = [];
110
+ for (const left of lefts) {
111
+ for (const right of rights) {
112
+ const probe = [];
113
+ // A fresh `seen` per probe: a pair rejected on one branch must not mark
114
+ // a reference pair visited for the next, which would silently pass it.
115
+ compare(left, right, path, probe, resolveRef, new Set(seen));
116
+ if (probe.length === 0)
117
+ return;
118
+ reasons.push(...probe);
119
+ }
120
+ }
121
+ issues.push(`${path || "/"}: no alternative matches — ${[...new Set(reasons)].join("; ")}`);
122
+ return;
123
+ }
83
124
  // Value types first: an `instance` representation has no JSON `type` to
84
125
  // compare, so its identity IS the comparison — and its arguments are where the
85
126
  // real information lives.
@@ -127,10 +168,6 @@ function compare(rawSource, rawTarget, path, issues, resolveRef, seen) {
127
168
  issues.push(`${path || "/"}: type mismatch — source is '${source.type}', target expects '${target.type}'`);
128
169
  return;
129
170
  }
130
- if (source.anyOf || source.oneOf || source.allOf)
131
- return;
132
- if (target.anyOf || target.oneOf || target.allOf)
133
- return;
134
171
  // An array's element, which the old comparison never looked at — so every
135
172
  // nested shape passed regardless of what it contained.
136
173
  if (target.items && source.items) {
@@ -370,8 +407,16 @@ export function celTypeSatisfiesJsonSchema(celType, schema) {
370
407
  }
371
408
  if (!schema.type && !schema.anyOf && !schema.oneOf && !schema.allOf)
372
409
  return true;
373
- if (schema.anyOf || schema.oneOf || schema.allOf)
410
+ // `allOf` is a conjunction and says too little to judge from a single CEL
411
+ // type. A union is a CHOICE, so it is satisfied by satisfying any branch —
412
+ // distributed for the same reason `compare` does it: accepting every union
413
+ // outright turns the check off for exactly the slots that admit more than one
414
+ // shape, and those are the ones where the branches carry the information.
415
+ if (schema.allOf)
374
416
  return true;
417
+ const branches = unionBranches(schema);
418
+ if (branches)
419
+ return branches.some((branch) => celTypeSatisfiesJsonSchema(celType, branch));
375
420
  const schemaTypes = Array.isArray(schema.type) ? schema.type : [schema.type];
376
421
  const accepted = {
377
422
  int: ["integer", "number"],
@@ -482,6 +527,24 @@ export function celPlaceholderForSchema(rawSchema) {
482
527
  // the real value is checked at runtime once the expression resolves.
483
528
  if (Array.isArray(schema.enum) && schema.enum.length > 0)
484
529
  return schema.enum[0];
530
+ // A UNION with no `type` of its own. Without this, a whole-field CEL leaf at
531
+ // such a slot gets `null`, which every branch then rejects — so a field
532
+ // declared `anyOf: [array, boolean]` could not be written as an expression at
533
+ // all, while one whose union happens to contain a `live` branch escaped by
534
+ // accident (nothing validates a live value, so `null` passed). The first
535
+ // branch that yields a placeholder wins: the same conservative posture
536
+ // `selectUnionBranch` takes, and enough for AJV, whose question is only
537
+ // whether SOME branch accepts the stand-in.
538
+ if (schema.type === undefined) {
539
+ const branches = unionBranches(schema);
540
+ if (branches) {
541
+ for (const branch of branches) {
542
+ const candidate = celPlaceholderForSchema(branch);
543
+ if (candidate !== null)
544
+ return candidate;
545
+ }
546
+ }
547
+ }
485
548
  switch (schema.type) {
486
549
  case "integer":
487
550
  case "number":
@@ -553,7 +616,7 @@ export function resolveRef(schema, root) {
553
616
  * — an ambiguous union is one the analyzer should not resolve on the author's
554
617
  * behalf.
555
618
  */
556
- function selectUnionBranch(schema, data, root) {
619
+ export function selectUnionBranch(schema, data, root) {
557
620
  const branches = (schema.oneOf ?? schema.anyOf);
558
621
  if (!Array.isArray(branches) || branches.length === 0)
559
622
  return schema;
@@ -1 +1 @@
1
- {"version":3,"file":"validate-cel-context.d.ts","sourceRoot":"","sources":["../src/validate-cel-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAItF,MAAM,WAAW,kBAAkB;IACjC;mEAC+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC;;kDAE8C;IAC9C,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;KACxD,CAAC;IACF,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;KAC/C,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CACtC;AA4CD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CA0EjC;AAuFD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAoBzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAChD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiJrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAQrB;AAWD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,SAAM,GACT,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CAGvD;AAUD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,SAAM,GAAG,MAAM,EAAE,CAqBxF"}
1
+ {"version":3,"file":"validate-cel-context.d.ts","sourceRoot":"","sources":["../src/validate-cel-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAStF,MAAM,WAAW,kBAAkB;IACjC;mEAC+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC;;kDAE8C;IAC9C,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;KACxD,CAAC;IACF,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;KAC/C,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;CACtC;AA4CD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnC,QAAQ,GAAE,WAAW,CAAC,MAAM,CAAa,GACxC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CA0EjC;AAyID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAoBzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAChD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA+JrB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAQrB;AAWD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,SAAM,GACT,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CAGvD;AAUD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,SAAM,GAAG,MAAM,EAAE,CAqBxF"}
@@ -1,5 +1,5 @@
1
1
  export { extractAccessChains, validateChainAgainstSchema } from "@telorun/templating";
2
- import { mergeTypeSchemas, parseCanonicalTypeSchemaId } from "@telorun/sdk";
2
+ import { elementSchemaOf, isLiveSlot, mergeTypeSchemas, parseCanonicalTypeSchemaId, } from "@telorun/sdk";
3
3
  import { KERNEL_BUILTINS } from "./builtins.js";
4
4
  /**
5
5
  * Resolve a type field value (string name, inline type, or raw schema) to a JSON Schema.
@@ -168,22 +168,64 @@ function schemaAtChain(chain, root) {
168
168
  }
169
169
  return cur && typeof cur === "object" ? cur : undefined;
170
170
  }
171
- /** The element schema of a sibling collection expression, when statically known.
172
- * Resolves `inputs.*` chains against the resource's `inputs:` contract and
173
- * returns the array's `items`. Returns undefined for non-chain or untyped
174
- * collections (caller substitutes `dyn`). */
175
- function resolveCollectionElementSchema(manifestRoot, field) {
171
+ /**
172
+ * The schema of a sibling collection expression, when statically known.
173
+ *
174
+ * Resolves `inputs.*` chains against the resource's DECLARED contract, falling
175
+ * back to the legacy `inputs:` property map some kinds still carry. Reading the
176
+ * contract is what makes this work at all for a kind that declares `inputType:`
177
+ * — resolving only the property map left `item` untyped in every such kind,
178
+ * silently, which reads as "element typing is permissive here" rather than as a
179
+ * gap. Returns undefined for a non-chain or untyped collection, and the caller
180
+ * substitutes `dyn` rather than inventing an element type.
181
+ */
182
+ function resolveCollectionSchema(manifestRoot, field, allManifests) {
176
183
  const chain = purePathChain(manifestRoot?.[field]);
177
184
  if (!chain || chain[0] !== "inputs")
178
185
  return undefined;
179
- const contract = manifestRoot.inputs;
180
- if (!contract || typeof contract !== "object")
186
+ const declared = resolveTypeFieldToSchema(manifestRoot.inputType, allManifests ?? []);
187
+ const root = declared && typeof declared === "object"
188
+ ? declared
189
+ : manifestRoot.inputs && typeof manifestRoot.inputs === "object"
190
+ ? { type: "object", properties: manifestRoot.inputs }
191
+ : undefined;
192
+ if (!root)
193
+ return undefined;
194
+ return schemaAtChain(chain.slice(1), root);
195
+ }
196
+ /**
197
+ * What ITERATING a collection schema yields.
198
+ *
199
+ * An array answers with `items`; anything else answers through the value-type
200
+ * vocabulary, which is where "what is the element of this" is declared. No type
201
+ * is named here on purpose: a future iterable value type is covered by declaring
202
+ * `element` on one of its parameters, with nothing to change in the analyzer.
203
+ */
204
+ function elementOfCollection(collection) {
205
+ if (!collection || typeof collection !== "object")
181
206
  return undefined;
182
- const terminal = schemaAtChain(chain.slice(1), { type: "object", properties: contract });
183
- if (terminal && terminal.type === "array" && terminal.items && typeof terminal.items === "object") {
184
- return terminal.items;
207
+ if (collection.type === "array") {
208
+ return collection.items && typeof collection.items === "object"
209
+ ? collection.items
210
+ : undefined;
185
211
  }
186
- return undefined;
212
+ const element = elementSchemaOf(collection);
213
+ return element && typeof element === "object" ? element : undefined;
214
+ }
215
+ /**
216
+ * True when a context binding naming this collection must NOT be bound.
217
+ *
218
+ * A binding that re-exposes the collection can only hand over the value the
219
+ * consumer is already draining, and passing that on is an ordinary
220
+ * pass-through no member-access rule catches — so the drain is silent. `live` is
221
+ * exactly the property that makes a value unsafe to re-expose, and it is already
222
+ * in the vocabulary, so no consumer names a type to decide this.
223
+ */
224
+ function collectionBindingWithheld(schema, manifestRoot, allManifests) {
225
+ const from = schema?.["x-telo-context-collection-from"];
226
+ if (!from)
227
+ return false;
228
+ return isLiveSlot(resolveCollectionSchema(manifestRoot, from, allManifests));
187
229
  }
188
230
  /**
189
231
  * Returns true when a CEL expression path (from walkCelExpressions, e.g. "routes[0].inputs.q")
@@ -297,9 +339,18 @@ export function resolveContextAnnotations(schema, manifestItem, opts) {
297
339
  // untyped sources fall back to `dyn` so a wrong element type is never invented.
298
340
  const elementFrom = schema["x-telo-context-element-from"];
299
341
  if (elementFrom) {
300
- const items = resolveCollectionElementSchema(manifestRoot, elementFrom);
342
+ const items = elementOfCollection(resolveCollectionSchema(manifestRoot, elementFrom, allManifests));
301
343
  return items ?? {};
302
344
  }
345
+ // The collection itself, as opposed to its element. Typed from whatever the
346
+ // sibling resolves to, so an array binding keeps the precision it has today
347
+ // instead of degrading to `dyn` now that the slot admits more than one shape.
348
+ // A `live` collection never reaches here — the property is dropped before
349
+ // recursion, so the name is simply not in scope.
350
+ const collectionFrom = schema["x-telo-context-collection-from"];
351
+ if (collectionFrom) {
352
+ return resolveCollectionSchema(manifestRoot, collectionFrom, allManifests) ?? {};
353
+ }
303
354
  const fromRoot = schema["x-telo-context-from-root"];
304
355
  const fromRefKindRaw = schema["x-telo-context-from-ref-kind"];
305
356
  const fromRefKinds = fromRefKindRaw == null
@@ -384,6 +435,11 @@ export function resolveContextAnnotations(schema, manifestItem, opts) {
384
435
  if (schema.properties) {
385
436
  const props = {};
386
437
  for (const [k, v] of Object.entries(schema.properties)) {
438
+ // Withholding happens HERE rather than inside the child resolver, because
439
+ // this is the only level that owns the property map — a child can return a
440
+ // schema but cannot remove itself from one.
441
+ if (collectionBindingWithheld(v, manifestRoot, allManifests))
442
+ continue;
387
443
  props[k] = resolveContextAnnotations(v, manifestItem, normalizedOpts);
388
444
  }
389
445
  return { ...schema, properties: props };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/analyzer",
3
- "version": "0.58.0",
3
+ "version": "0.59.0",
4
4
  "description": "Telo Analyzer - Static manifest validator for Telo manifests.",
5
5
  "keywords": [
6
6
  "telo",
@@ -43,13 +43,13 @@
43
43
  "jsonpath-plus": "^10.3.0",
44
44
  "packageurl-js": "^2.0.1",
45
45
  "yaml": "^2.8.3",
46
- "@telorun/templating": "0.14.0"
46
+ "@telorun/templating": "0.15.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^20.0.0",
50
50
  "typescript": "^5.0.0",
51
51
  "vitest": "^2.1.8",
52
- "@telorun/sdk": "0.73.0"
52
+ "@telorun/sdk": "0.74.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@telorun/sdk": "*"
package/src/index.ts CHANGED
@@ -62,12 +62,19 @@ export {
62
62
  export type { ContractDirection, DefResolver } from "./extends-resolution.js";
63
63
  export {
64
64
  defaultBearingPaths,
65
+ declaredScalarPaths,
65
66
  PERMISSIVE_CONTRACT,
66
67
  resolveContract,
67
68
  resolveContractSchema,
68
69
  withLiveValuesSkipped,
69
70
  } from "./invocation-contract.js";
70
- export type { ContractOrigin, ContractScope, ResolvedContract } from "./invocation-contract.js";
71
+ export type {
72
+ ContractOrigin,
73
+ ContractScope,
74
+ DeclaredScalarForm,
75
+ DeclaredScalarPath,
76
+ ResolvedContract,
77
+ } from "./invocation-contract.js";
71
78
  export {
72
79
  hasIntermediateWildcard,
73
80
  parseRedactionPath,
@@ -136,7 +143,7 @@ export { validateDynamicSelectors, validateRefSlotDeclarations } from "./validat
136
143
  export type { RefSlotIssue } from "./validate-ref-slots.js";
137
144
  export { validateValueTypeSlots } from "./validate-value-type-slots.js";
138
145
  export type { ValueTypeSlotIssue } from "./validate-value-type-slots.js";
139
- export { checkSchemaCompatibility } from "./schema-compat.js";
146
+ export { checkSchemaCompatibility, selectUnionBranch } from "./schema-compat.js";
140
147
  export type { CompatibilityResult } from "./schema-compat.js";
141
148
  export { visitManifest } from "./manifest-visitor.js";
142
149
  export type {
@@ -1,4 +1,4 @@
1
- import { isLiveSlot, type ResourceDefinition } from "@telorun/sdk";
1
+ import { isLiveSlot, type ResourceDefinition, valueTypeOf } from "@telorun/sdk";
2
2
  import {
3
3
  type ContractDirection,
4
4
  contractDeclarer,
@@ -268,3 +268,94 @@ export function defaultBearingPaths(
268
268
  walk(schema, [], []);
269
269
  return out;
270
270
  }
271
+
272
+ /** The scalar form a declared node's value takes at runtime. `int64` and
273
+ * `double` are the two JSON scalars whose runtime representation is NOT decided
274
+ * by the value that arrives: a CEL integer is a BigInt and a CEL double a JS
275
+ * number, and both are `typeof "number" | "bigint"` away from what a declaration
276
+ * says they are. Everything else — string, boolean, object, array, and every
277
+ * `instance` value type — is already its own representation, so it is not
278
+ * listed and never rewritten. */
279
+ export type DeclaredScalarForm = "int64" | "double";
280
+
281
+ export interface DeclaredScalarPath {
282
+ readonly path: string[];
283
+ readonly form: DeclaredScalarForm;
284
+ }
285
+
286
+ /** Every path in `schema` whose declared type fixes a scalar representation —
287
+ * the leaves a value must carry in that form for the contract to be TRUE, not
288
+ * merely to pass.
289
+ *
290
+ * A declared shape says what the value IS, the same service a JSON Schema gives
291
+ * an HTTP response serializer. Telo's CEL layer takes it literally:
292
+ * `jsonSchemaToCelType` maps `integer` to CEL `int` and `number` to `double`,
293
+ * and a CEL int IS a BigInt — so a controller handing back a plain JS number at
294
+ * an `integer` slot makes the declaration a lie that surfaces nowhere until an
295
+ * expression composes it, as `result.n + 1` type-checking statically and then
296
+ * dying at dispatch with `no such overload: dyn<double> + int`.
297
+ *
298
+ * A VALUE TYPE is read through the same rule rather than beside it: a `json`
299
+ * representation refines a JSON type and contributes its `base` (so
300
+ * `Telo.TcpPort` is an `int64` slot), while an `instance` representation
301
+ * REPLACES the JSON layer — a byte buffer and a stream handle are already their
302
+ * own representation, nothing converts to them, and the walk stops there rather
303
+ * than descending into a value that is not a plain container.
304
+ *
305
+ * Bounded by the schema's declarations rather than by the size of the payload,
306
+ * exactly as {@link defaultBearingPaths} is: a contract declaring no such
307
+ * scalar walks nothing at dispatch. A union counts when it names exactly one of
308
+ * the two — `["integer", "null"]` is still the integer branch, while
309
+ * `["integer", "number"]` fixes nothing and is left alone. */
310
+ export function declaredScalarPaths(
311
+ schema: Record<string, any>,
312
+ resolveRef?: (ref: string) => Record<string, any> | undefined,
313
+ ): DeclaredScalarPath[] {
314
+ const out: DeclaredScalarPath[] = [];
315
+
316
+ const walk = (node: unknown, path: string[], chain: readonly object[]): void => {
317
+ if (!node || typeof node !== "object") return;
318
+ let s = node as Record<string, any>;
319
+ if (chain.includes(s)) return;
320
+ if (resolveRef && typeof s.$ref === "string") {
321
+ const target = resolveRef(s.$ref);
322
+ if (!target || chain.includes(target)) return;
323
+ s = { ...target, ...s, $ref: undefined };
324
+ }
325
+ const here = [...chain, node as object];
326
+
327
+ const entry = valueTypeOf(s);
328
+ // An `instance` representation replaces the JSON layer: it is its own
329
+ // representation, so there is nothing to normalize to and nothing below it
330
+ // that is a plain container to walk.
331
+ if (entry && entry.representation === "instance") return;
332
+
333
+ const form = scalarFormOf(entry && entry.base !== undefined ? entry.base : s.type);
334
+ if (form && path.length > 0) out.push({ path, form });
335
+
336
+ const properties = s.properties as Record<string, any> | undefined;
337
+ if (properties) {
338
+ for (const [key, child] of Object.entries(properties)) walk(child, [...path, key], here);
339
+ }
340
+ for (const branch of ["allOf", "anyOf", "oneOf"] as const) {
341
+ const list = s[branch];
342
+ if (Array.isArray(list)) for (const child of list) walk(child, path, here);
343
+ }
344
+ if (s.items) walk(s.items, [...path, "[]"], here);
345
+ };
346
+
347
+ walk(schema, [], []);
348
+ return out;
349
+ }
350
+
351
+ function scalarFormOf(declared: unknown): DeclaredScalarForm | undefined {
352
+ if (declared === "integer") return "int64";
353
+ if (declared === "number") return "double";
354
+ if (!Array.isArray(declared)) return undefined;
355
+ const integer = declared.includes("integer");
356
+ const number = declared.includes("number");
357
+ // A union naming both fixes nothing — either representation satisfies it, so
358
+ // rewriting one into the other would be a choice the declaration never made.
359
+ if (integer === number) return undefined;
360
+ return integer ? "int64" : "double";
361
+ }
@@ -48,6 +48,16 @@ export interface CompatibilityResult {
48
48
  issues: string[];
49
49
  }
50
50
 
51
+ /** The alternatives a union node declares, or undefined when it is not one.
52
+ * `anyOf` and `oneOf` are one question here — which branches could accept this
53
+ * value — and their difference (exactly-one vs at-least-one) is a validation
54
+ * rule, not a compatibility one. */
55
+ function unionBranches(schema: Record<string, any>): Record<string, any>[] | undefined {
56
+ const branches = schema.anyOf ?? schema.oneOf;
57
+ if (!Array.isArray(branches) || branches.length === 0) return undefined;
58
+ return branches.filter((b) => b && typeof b === "object") as Record<string, any>[];
59
+ }
60
+
51
61
  /**
52
62
  * Conservative structural JSON Schema compatibility check — is a value shaped
53
63
  * like `source` acceptable where `target` is declared?
@@ -115,6 +125,38 @@ function compare(
115
125
  const source = deref(rawSource, resolveRef);
116
126
  const target = deref(rawTarget, resolveRef);
117
127
 
128
+ // A union is ALTERNATIVES, so it is compared by distributing over branches on
129
+ // both sides: a definite conflict is one where no source-branch/target-branch
130
+ // pair agrees. Returning silently the moment either side was a union — which
131
+ // is what this did — switched the whole comparison off for any slot that
132
+ // accepts more than one shape, and those are exactly the slots where a value
133
+ // type carries the only information distinguishing the branches.
134
+ //
135
+ // `allOf` is a conjunction rather than a choice, so it keeps the old posture:
136
+ // it says too little to judge and stays compatible.
137
+ if (source.allOf || target.allOf) return;
138
+ const sourceBranches = unionBranches(source);
139
+ const targetBranches = unionBranches(target);
140
+ if (sourceBranches || targetBranches) {
141
+ const lefts = sourceBranches ?? [source];
142
+ const rights = targetBranches ?? [target];
143
+ const reasons: string[] = [];
144
+ for (const left of lefts) {
145
+ for (const right of rights) {
146
+ const probe: string[] = [];
147
+ // A fresh `seen` per probe: a pair rejected on one branch must not mark
148
+ // a reference pair visited for the next, which would silently pass it.
149
+ compare(left, right, path, probe, resolveRef, new Set(seen));
150
+ if (probe.length === 0) return;
151
+ reasons.push(...probe);
152
+ }
153
+ }
154
+ issues.push(
155
+ `${path || "/"}: no alternative matches — ${[...new Set(reasons)].join("; ")}`,
156
+ );
157
+ return;
158
+ }
159
+
118
160
  // Value types first: an `instance` representation has no JSON `type` to
119
161
  // compare, so its identity IS the comparison — and its arguments are where the
120
162
  // real information lives.
@@ -180,8 +222,6 @@ function compare(
180
222
  );
181
223
  return;
182
224
  }
183
- if (source.anyOf || source.oneOf || source.allOf) return;
184
- if (target.anyOf || target.oneOf || target.allOf) return;
185
225
 
186
226
  // An array's element, which the old comparison never looked at — so every
187
227
  // nested shape passed regardless of what it contained.
@@ -425,7 +465,14 @@ export function celTypeSatisfiesJsonSchema(celType: string, schema: Record<strin
425
465
  return true;
426
466
  }
427
467
  if (!schema.type && !schema.anyOf && !schema.oneOf && !schema.allOf) return true;
428
- if (schema.anyOf || schema.oneOf || schema.allOf) return true;
468
+ // `allOf` is a conjunction and says too little to judge from a single CEL
469
+ // type. A union is a CHOICE, so it is satisfied by satisfying any branch —
470
+ // distributed for the same reason `compare` does it: accepting every union
471
+ // outright turns the check off for exactly the slots that admit more than one
472
+ // shape, and those are the ones where the branches carry the information.
473
+ if (schema.allOf) return true;
474
+ const branches = unionBranches(schema);
475
+ if (branches) return branches.some((branch) => celTypeSatisfiesJsonSchema(celType, branch));
429
476
  const schemaTypes = Array.isArray(schema.type) ? schema.type : [schema.type];
430
477
  const accepted: Record<string, string[]> = {
431
478
  int: ["integer", "number"],
@@ -528,6 +575,23 @@ export function celPlaceholderForSchema(rawSchema: Record<string, any>): unknown
528
575
  // member chosen is irrelevant — only its acceptability to AJV matters, since
529
576
  // the real value is checked at runtime once the expression resolves.
530
577
  if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
578
+ // A UNION with no `type` of its own. Without this, a whole-field CEL leaf at
579
+ // such a slot gets `null`, which every branch then rejects — so a field
580
+ // declared `anyOf: [array, boolean]` could not be written as an expression at
581
+ // all, while one whose union happens to contain a `live` branch escaped by
582
+ // accident (nothing validates a live value, so `null` passed). The first
583
+ // branch that yields a placeholder wins: the same conservative posture
584
+ // `selectUnionBranch` takes, and enough for AJV, whose question is only
585
+ // whether SOME branch accepts the stand-in.
586
+ if (schema.type === undefined) {
587
+ const branches = unionBranches(schema);
588
+ if (branches) {
589
+ for (const branch of branches) {
590
+ const candidate = celPlaceholderForSchema(branch);
591
+ if (candidate !== null) return candidate;
592
+ }
593
+ }
594
+ }
531
595
  switch (schema.type) {
532
596
  case "integer":
533
597
  case "number":
@@ -603,7 +667,7 @@ export function resolveRef(schema: Record<string, any>, root: Record<string, any
603
667
  * — an ambiguous union is one the analyzer should not resolve on the author's
604
668
  * behalf.
605
669
  */
606
- function selectUnionBranch(
670
+ export function selectUnionBranch(
607
671
  schema: Record<string, any>,
608
672
  data: unknown,
609
673
  root: Record<string, any>,
@@ -1,5 +1,10 @@
1
1
  export { extractAccessChains, validateChainAgainstSchema } from "@telorun/templating";
2
- import { mergeTypeSchemas, parseCanonicalTypeSchemaId } from "@telorun/sdk";
2
+ import {
3
+ elementSchemaOf,
4
+ isLiveSlot,
5
+ mergeTypeSchemas,
6
+ parseCanonicalTypeSchemaId,
7
+ } from "@telorun/sdk";
3
8
  import { KERNEL_BUILTINS } from "./builtins.js";
4
9
 
5
10
  export interface ContextResolveOpts {
@@ -206,23 +211,73 @@ function schemaAtChain(
206
211
  return cur && typeof cur === "object" ? cur : undefined;
207
212
  }
208
213
 
209
- /** The element schema of a sibling collection expression, when statically known.
210
- * Resolves `inputs.*` chains against the resource's `inputs:` contract and
211
- * returns the array's `items`. Returns undefined for non-chain or untyped
212
- * collections (caller substitutes `dyn`). */
213
- function resolveCollectionElementSchema(
214
+ /**
215
+ * The schema of a sibling collection expression, when statically known.
216
+ *
217
+ * Resolves `inputs.*` chains against the resource's DECLARED contract, falling
218
+ * back to the legacy `inputs:` property map some kinds still carry. Reading the
219
+ * contract is what makes this work at all for a kind that declares `inputType:`
220
+ * — resolving only the property map left `item` untyped in every such kind,
221
+ * silently, which reads as "element typing is permissive here" rather than as a
222
+ * gap. Returns undefined for a non-chain or untyped collection, and the caller
223
+ * substitutes `dyn` rather than inventing an element type.
224
+ */
225
+ function resolveCollectionSchema(
214
226
  manifestRoot: Record<string, any>,
215
227
  field: string,
228
+ allManifests: Record<string, any>[] | undefined,
216
229
  ): Record<string, any> | undefined {
217
230
  const chain = purePathChain(manifestRoot?.[field]);
218
231
  if (!chain || chain[0] !== "inputs") return undefined;
219
- const contract = manifestRoot.inputs;
220
- if (!contract || typeof contract !== "object") return undefined;
221
- const terminal = schemaAtChain(chain.slice(1), { type: "object", properties: contract });
222
- if (terminal && terminal.type === "array" && terminal.items && typeof terminal.items === "object") {
223
- return terminal.items as Record<string, any>;
232
+ const declared = resolveTypeFieldToSchema(manifestRoot.inputType, allManifests ?? []);
233
+ const root =
234
+ declared && typeof declared === "object"
235
+ ? declared
236
+ : manifestRoot.inputs && typeof manifestRoot.inputs === "object"
237
+ ? { type: "object", properties: manifestRoot.inputs }
238
+ : undefined;
239
+ if (!root) return undefined;
240
+ return schemaAtChain(chain.slice(1), root);
241
+ }
242
+
243
+ /**
244
+ * What ITERATING a collection schema yields.
245
+ *
246
+ * An array answers with `items`; anything else answers through the value-type
247
+ * vocabulary, which is where "what is the element of this" is declared. No type
248
+ * is named here on purpose: a future iterable value type is covered by declaring
249
+ * `element` on one of its parameters, with nothing to change in the analyzer.
250
+ */
251
+ function elementOfCollection(
252
+ collection: Record<string, any> | undefined,
253
+ ): Record<string, any> | undefined {
254
+ if (!collection || typeof collection !== "object") return undefined;
255
+ if (collection.type === "array") {
256
+ return collection.items && typeof collection.items === "object"
257
+ ? (collection.items as Record<string, any>)
258
+ : undefined;
224
259
  }
225
- return undefined;
260
+ const element = elementSchemaOf(collection);
261
+ return element && typeof element === "object" ? (element as Record<string, any>) : undefined;
262
+ }
263
+
264
+ /**
265
+ * True when a context binding naming this collection must NOT be bound.
266
+ *
267
+ * A binding that re-exposes the collection can only hand over the value the
268
+ * consumer is already draining, and passing that on is an ordinary
269
+ * pass-through no member-access rule catches — so the drain is silent. `live` is
270
+ * exactly the property that makes a value unsafe to re-expose, and it is already
271
+ * in the vocabulary, so no consumer names a type to decide this.
272
+ */
273
+ function collectionBindingWithheld(
274
+ schema: Record<string, any>,
275
+ manifestRoot: Record<string, any>,
276
+ allManifests: Record<string, any>[] | undefined,
277
+ ): boolean {
278
+ const from = schema?.["x-telo-context-collection-from"] as string | undefined;
279
+ if (!from) return false;
280
+ return isLiveSlot(resolveCollectionSchema(manifestRoot, from, allManifests));
226
281
  }
227
282
 
228
283
  /**
@@ -342,10 +397,20 @@ export function resolveContextAnnotations(
342
397
  // untyped sources fall back to `dyn` so a wrong element type is never invented.
343
398
  const elementFrom = schema["x-telo-context-element-from"] as string | undefined;
344
399
  if (elementFrom) {
345
- const items = resolveCollectionElementSchema(manifestRoot, elementFrom);
400
+ const items = elementOfCollection(resolveCollectionSchema(manifestRoot, elementFrom, allManifests));
346
401
  return items ?? {};
347
402
  }
348
403
 
404
+ // The collection itself, as opposed to its element. Typed from whatever the
405
+ // sibling resolves to, so an array binding keeps the precision it has today
406
+ // instead of degrading to `dyn` now that the slot admits more than one shape.
407
+ // A `live` collection never reaches here — the property is dropped before
408
+ // recursion, so the name is simply not in scope.
409
+ const collectionFrom = schema["x-telo-context-collection-from"] as string | undefined;
410
+ if (collectionFrom) {
411
+ return resolveCollectionSchema(manifestRoot, collectionFrom, allManifests) ?? {};
412
+ }
413
+
349
414
  const fromRoot = schema["x-telo-context-from-root"] as string | undefined;
350
415
  const fromRefKindRaw = schema["x-telo-context-from-ref-kind"] as
351
416
  | string
@@ -445,6 +510,10 @@ export function resolveContextAnnotations(
445
510
  if (schema.properties) {
446
511
  const props: Record<string, any> = {};
447
512
  for (const [k, v] of Object.entries(schema.properties)) {
513
+ // Withholding happens HERE rather than inside the child resolver, because
514
+ // this is the only level that owns the property map — a child can return a
515
+ // schema but cannot remove itself from one.
516
+ if (collectionBindingWithheld(v as Record<string, any>, manifestRoot, allManifests)) continue;
448
517
  props[k] = resolveContextAnnotations(v as Record<string, any>, manifestItem, normalizedOpts);
449
518
  }
450
519
  return { ...schema, properties: props };