@telorun/analyzer 0.59.0 → 0.60.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/analyzer.d.ts +9 -2
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +38 -10
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +16 -42
- package/dist/cel-environment.d.ts.map +1 -1
- package/dist/cel-environment.js +35 -0
- package/dist/flatten-for-analyzer.d.ts +4 -0
- package/dist/flatten-for-analyzer.d.ts.map +1 -1
- package/dist/flatten-for-analyzer.js +8 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/kernel-globals.d.ts +1 -1
- package/dist/kernel-globals.d.ts.map +1 -1
- package/dist/kernel-globals.js +15 -1
- package/dist/manifest-schemas.d.ts +407 -0
- package/dist/manifest-schemas.d.ts.map +1 -0
- package/dist/manifest-schemas.js +396 -0
- package/dist/module-file-claims.d.ts +6 -0
- package/dist/module-file-claims.d.ts.map +1 -1
- package/dist/module-file-claims.js +4 -0
- package/dist/module-metadata-scope.d.ts +44 -0
- package/dist/module-metadata-scope.d.ts.map +1 -0
- package/dist/module-metadata-scope.js +82 -0
- package/dist/parse-loaded-file.d.ts.map +1 -1
- package/dist/parse-loaded-file.js +16 -0
- package/dist/release/bump-level.d.ts +46 -0
- package/dist/release/bump-level.d.ts.map +1 -0
- package/dist/release/bump-level.js +80 -0
- package/dist/release/changelog.d.ts +36 -0
- package/dist/release/changelog.d.ts.map +1 -0
- package/dist/release/changelog.js +53 -0
- package/dist/release/fragment.d.ts +48 -0
- package/dist/release/fragment.d.ts.map +1 -0
- package/dist/release/fragment.js +84 -0
- package/dist/release/index.d.ts +26 -0
- package/dist/release/index.d.ts.map +1 -0
- package/dist/release/index.js +18 -0
- package/dist/release/ledger.d.ts +53 -0
- package/dist/release/ledger.d.ts.map +1 -0
- package/dist/release/ledger.js +109 -0
- package/dist/release/payload-digest.d.ts +63 -0
- package/dist/release/payload-digest.d.ts.map +1 -0
- package/dist/release/payload-digest.js +65 -0
- package/dist/release/release-plan.d.ts +128 -0
- package/dist/release/release-plan.d.ts.map +1 -0
- package/dist/release/release-plan.js +277 -0
- package/dist/release/version-stamp.d.ts +50 -0
- package/dist/release/version-stamp.d.ts.map +1 -0
- package/dist/release/version-stamp.js +119 -0
- package/dist/release/workspace-config.d.ts +41 -0
- package/dist/release/workspace-config.d.ts.map +1 -0
- package/dist/release/workspace-config.js +60 -0
- package/dist/schema-compat.js +2 -1
- package/dist/validate-step-inputs.d.ts +1 -1
- package/dist/validate-step-inputs.d.ts.map +1 -1
- package/dist/validate-step-inputs.js +99 -8
- package/package.json +3 -3
- package/src/analyzer.ts +41 -10
- package/src/builtins.ts +16 -42
- package/src/cel-environment.ts +37 -0
- package/src/flatten-for-analyzer.ts +12 -0
- package/src/index.ts +9 -1
- package/src/kernel-globals.ts +23 -1
- package/src/manifest-schemas.ts +408 -0
- package/src/module-file-claims.ts +10 -0
- package/src/module-metadata-scope.ts +88 -0
- package/src/parse-loaded-file.ts +16 -0
- package/src/release/bump-level.ts +95 -0
- package/src/release/changelog.ts +62 -0
- package/src/release/fragment.ts +130 -0
- package/src/release/index.ts +66 -0
- package/src/release/ledger.ts +142 -0
- package/src/release/payload-digest.ts +83 -0
- package/src/release/release-plan.ts +392 -0
- package/src/release/version-stamp.ts +142 -0
- package/src/release/workspace-config.ts +81 -0
- package/src/schema-compat.ts +1 -1
- package/src/validate-step-inputs.ts +109 -9
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
validateAgainstSchema,
|
|
10
10
|
} from "./schema-compat.js";
|
|
11
11
|
import { plainChainOf } from "@telorun/templating";
|
|
12
|
-
import { valueTypeOf } from "@telorun/sdk";
|
|
12
|
+
import { isLiveSlot, valueTypeOf } from "@telorun/sdk";
|
|
13
|
+
import { manifestFragmentOf } from "./manifest-schemas.js";
|
|
13
14
|
import {
|
|
14
15
|
analyzerContractScope,
|
|
15
16
|
containerOf,
|
|
@@ -25,7 +26,7 @@ export interface StepInputIssue {
|
|
|
25
26
|
message: string;
|
|
26
27
|
/** Set when the issue is a type-argument disagreement rather than a contract
|
|
27
28
|
* shape violation — the two read differently and deserve their own code. */
|
|
28
|
-
code?: "CEL_TYPE_ARGUMENT_MISMATCH";
|
|
29
|
+
code?: "CEL_TYPE_ARGUMENT_MISMATCH" | "LIVE_VALUE_RETRIED";
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
|
|
@@ -118,15 +119,30 @@ export function collectStepInputIssues(
|
|
|
118
119
|
// that silence is exactly where a stream of the wrong element used to
|
|
119
120
|
// flow. The comparison is covariant and gradual: an omitted argument is
|
|
120
121
|
// *any* in both directions, so only a definite conflict is reported.
|
|
121
|
-
|
|
122
|
+
// The roots a plain chain may name here, each paired with the schema it is
|
|
123
|
+
// navigated against. `steps.` is the step map (analyzer state, supplied by
|
|
124
|
+
// the caller). `inputs.` is the ENCLOSING kind's own declared inputType,
|
|
125
|
+
// which is how a value produced OUTSIDE this resource reaches a step at
|
|
126
|
+
// all: an HTTP route maps `request.body` into its handler's inputs, and the
|
|
127
|
+
// handler forwards `inputs.body` onward — the shape a live value most often
|
|
128
|
+
// arrives in, and the one covering only `steps.` missed entirely. A root
|
|
129
|
+
// this cannot resolve contributes nothing rather than guessing at a schema.
|
|
130
|
+
const roots: Array<[string, Record<string, any>]> = [];
|
|
131
|
+
if (stepContext) roots.push(["steps.", stepContext]);
|
|
132
|
+
const ownContract = resolveContract(
|
|
133
|
+
"inputType",
|
|
134
|
+
manifest,
|
|
135
|
+
contractScope.resolveIn(manifest.kind as string, readingModule),
|
|
136
|
+
contractScope,
|
|
137
|
+
);
|
|
138
|
+
if (ownContract) roots.push(["inputs.", ownContract.schema]);
|
|
139
|
+
|
|
140
|
+
if (roots.length > 0) {
|
|
122
141
|
for (const [inputName, inputValue] of Object.entries(values)) {
|
|
123
142
|
const chain = plainChainOf(inputValue);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
// guessing at a root this does not hold would compare the wrong schema.
|
|
128
|
-
if (!chain?.startsWith("steps.")) continue;
|
|
129
|
-
const produced = navigateSchemaToExprPath(stepContext, chain.slice("steps.".length));
|
|
143
|
+
const root = chain ? roots.find(([prefix]) => chain.startsWith(prefix)) : undefined;
|
|
144
|
+
if (!chain || !root) continue;
|
|
145
|
+
const produced = navigateSchemaToExprPath(root[1], chain.slice(root[0].length));
|
|
130
146
|
const slotSchema = (contract.schema.properties as Record<string, any> | undefined)?.[
|
|
131
147
|
inputName
|
|
132
148
|
];
|
|
@@ -138,6 +154,28 @@ export function collectStepInputIssues(
|
|
|
138
154
|
// broad new Error-severity check hidden behind an argument-specific
|
|
139
155
|
// name. Both sides must declare a value type for the question to be
|
|
140
156
|
// about arguments at all.
|
|
157
|
+
// A LIVE value is consumed by reading, so it exists exactly once —
|
|
158
|
+
// that is what `live` says in the vocabulary, and re-attempting a
|
|
159
|
+
// dispatch that already read it re-sends nothing. Reported here rather
|
|
160
|
+
// than through a slot-specific annotation because both facts are
|
|
161
|
+
// already declared: the value's liveness by its value type, and the
|
|
162
|
+
// re-attempt by the retry policy. No kind is named.
|
|
163
|
+
if (isLiveSlot(produced)) {
|
|
164
|
+
const retry = declaredRetry(step, stepItemSchema, invokedManifest, invokedDef);
|
|
165
|
+
if (retry !== undefined) {
|
|
166
|
+
out.push({
|
|
167
|
+
path: `${stepPath}.${inputsField}.${inputName}`,
|
|
168
|
+
targetLabel: invokedName ?? invokedKind ?? "the invoked resource",
|
|
169
|
+
message:
|
|
170
|
+
`'${inputName}' is a live value, which is consumed by reading and so exists ` +
|
|
171
|
+
`once — but ${retry} re-attempts the dispatch, and a re-attempt would pass ` +
|
|
172
|
+
`nothing. Collect it to a value first, or chunk the work so each attempt ` +
|
|
173
|
+
`carries its own replayable piece.`,
|
|
174
|
+
code: "LIVE_VALUE_RETRIED",
|
|
175
|
+
});
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
141
179
|
if (!valueTypeOf(produced) || !valueTypeOf(slotSchema)) continue;
|
|
142
180
|
const { compatible, issues } = checkSchemaCompatibility(produced, slotSchema, (ref) =>
|
|
143
181
|
defs.schemaForId(ref),
|
|
@@ -170,3 +208,65 @@ export function collectStepInputIssues(
|
|
|
170
208
|
return out;
|
|
171
209
|
}
|
|
172
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Where a re-attempt is declared for this dispatch, described for a diagnostic,
|
|
213
|
+
* or undefined when none is.
|
|
214
|
+
*
|
|
215
|
+
* A field declares one when its schema was expanded from a shared retry fragment
|
|
216
|
+
* — the shape the author pointed at, rather than a marker they had to remember to
|
|
217
|
+
* write beside it. Which fragment also says WHERE the budget is, so the two
|
|
218
|
+
* spellings a kind may carry (a policy object, or the deprecated bare count) need
|
|
219
|
+
* no guessing between them and no rule about which one wins.
|
|
220
|
+
*
|
|
221
|
+
* Two sites are consulted because there are two real ones: the STEP's own policy
|
|
222
|
+
* — `retry` on the kernel-owned dispatch site — and the TARGET's, a field on an
|
|
223
|
+
* arbitrary kind, because `Http.Request` re-attempts inside its own `invoke()`
|
|
224
|
+
* where only it can tell a 429 from a 500. A live value is equally doomed by
|
|
225
|
+
* either. EVERY retry-bearing field at a site is checked, not the first, since
|
|
226
|
+
* `Http.Request` carries both spellings and property order must not decide which
|
|
227
|
+
* is seen.
|
|
228
|
+
*
|
|
229
|
+
* Only a STATICALLY KNOWN non-zero budget counts. An `attempts` written as CEL
|
|
230
|
+
* says nothing here, and guessing would report a conflict against a manifest that
|
|
231
|
+
* may never retry — the same posture the `use` case-map selector takes.
|
|
232
|
+
*/
|
|
233
|
+
function declaredRetry(
|
|
234
|
+
step: Record<string, any>,
|
|
235
|
+
stepItemSchema: Record<string, any> | undefined,
|
|
236
|
+
invokedManifest: Record<string, any> | undefined,
|
|
237
|
+
invokedDef: Record<string, any> | undefined,
|
|
238
|
+
): string | undefined {
|
|
239
|
+
for (const [field, budget] of retryFields(stepItemSchema)) {
|
|
240
|
+
if (budget(step?.[field]) > 0) return `the step's \`${field}\``;
|
|
241
|
+
}
|
|
242
|
+
for (const [field, budget] of retryFields(invokedDef?.schema as Record<string, any>)) {
|
|
243
|
+
if (budget(invokedManifest?.[field]) > 0) return `the target's \`${field}\``;
|
|
244
|
+
}
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** How each shared retry fragment carries its budget. Keyed on fragment name —
|
|
249
|
+
* the analyzer's own built-ins, never a module's kind — so a kind that adopts a
|
|
250
|
+
* shape is covered without naming it here. */
|
|
251
|
+
const RETRY_BUDGET: Record<string, (value: unknown) => number> = {
|
|
252
|
+
RetryPolicy: (value) => {
|
|
253
|
+
if (!value || typeof value !== "object") return 0;
|
|
254
|
+
const attempts = (value as Record<string, unknown>).attempts;
|
|
255
|
+
return typeof attempts === "number" ? attempts : 0;
|
|
256
|
+
},
|
|
257
|
+
RetryAttempts: (value) => (typeof value === "number" ? value : 0),
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/** Every property of `schema` whose shape came from a retry fragment, paired with
|
|
261
|
+
* the reader for that fragment's budget. */
|
|
262
|
+
function retryFields(
|
|
263
|
+
schema: Record<string, any> | undefined,
|
|
264
|
+
): Array<[string, (value: unknown) => number]> {
|
|
265
|
+
if (!schema) return [];
|
|
266
|
+
const out: Array<[string, (value: unknown) => number]> = [];
|
|
267
|
+
for (const [key, sub] of gatherPropertySchemas(schema)) {
|
|
268
|
+
const budget = RETRY_BUDGET[manifestFragmentOf(sub) ?? ""];
|
|
269
|
+
if (budget) out.push([key, budget]);
|
|
270
|
+
}
|
|
271
|
+
return out;
|
|
272
|
+
}
|