@telorun/sdk 0.86.0 → 0.90.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.
@@ -17,7 +17,7 @@ export interface DispatchContext extends RefResolveContext {
17
17
  ensureKindRef?(value: unknown): KindRef;
18
18
  }
19
19
  /**
20
- * Resolve a decorator's `invoke:` field to a live invocable and return a thunk
20
+ * Resolve a decorator's `invoke:` field to a live executable and return a thunk
21
21
  * that dispatches it through the traced chokepoint. The field is either a
22
22
  * Phase-5-injected instance or a raw `{ kind, name, alias }` ref resolved
23
23
  * against the module context. Resolution is eager (fail-fast on a bad ref);
@@ -26,6 +26,11 @@ export interface DispatchContext extends RefResolveContext {
26
26
  * The thunk's optional second argument seeds the dispatch's {@link InvokeContext}
27
27
  * (e.g. a decorator-owned cancellation scope); when omitted the ambient
28
28
  * invocation context applies unchanged.
29
+ *
30
+ * The target is anything a step's `invoke:` accepts: an instance with `invoke()`
31
+ * or, run-only, with `run()`. Both go to `invokeResolved`, which calls `run()`
32
+ * when there is no `invoke()` — so a run-only target is started exactly as a
33
+ * step starts it, and the inputs it cannot take are dropped there, not here.
29
34
  */
30
35
  export declare function resolveInvocableDispatcher(field: unknown, ctx: DispatchContext, describe: () => string): (inputs: Record<string, unknown>, invokeCtx?: InvokeContext) => Promise<unknown>;
31
36
  //# sourceMappingURL=dispatch-invoke-ref.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-invoke-ref.d.ts","sourceRoot":"","sources":["../src/dispatch-invoke-ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/E,4EAA4E;AAC5E,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,cAAc,CAAC,OAAO,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,OAAO,EACf,GAAG,CAAC,EAAE,aAAa,GAClB,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC;;;;;;OAMG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CACzC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,MAAM,MAAM,GACrB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAyBlF"}
1
+ {"version":3,"file":"dispatch-invoke-ref.d.ts","sourceRoot":"","sources":["../src/dispatch-invoke-ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG/E,4EAA4E;AAC5E,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,cAAc,CAAC,OAAO,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,OAAO,EACf,GAAG,CAAC,EAAE,aAAa,GAClB,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC;;;;;;OAMG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CACzC;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,MAAM,MAAM,GACrB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CA8ClF"}
@@ -1,7 +1,8 @@
1
1
  import { resolveRefInstance } from "./resolve-ref-instance.js";
2
2
  import { getRefIdentity } from "./resource-instance.js";
3
+ import { RuntimeError } from "./types.js";
3
4
  /**
4
- * Resolve a decorator's `invoke:` field to a live invocable and return a thunk
5
+ * Resolve a decorator's `invoke:` field to a live executable and return a thunk
5
6
  * that dispatches it through the traced chokepoint. The field is either a
6
7
  * Phase-5-injected instance or a raw `{ kind, name, alias }` ref resolved
7
8
  * against the module context. Resolution is eager (fail-fast on a bad ref);
@@ -10,26 +11,48 @@ import { getRefIdentity } from "./resource-instance.js";
10
11
  * The thunk's optional second argument seeds the dispatch's {@link InvokeContext}
11
12
  * (e.g. a decorator-owned cancellation scope); when omitted the ambient
12
13
  * invocation context applies unchanged.
14
+ *
15
+ * The target is anything a step's `invoke:` accepts: an instance with `invoke()`
16
+ * or, run-only, with `run()`. Both go to `invokeResolved`, which calls `run()`
17
+ * when there is no `invoke()` — so a run-only target is started exactly as a
18
+ * step starts it, and the inputs it cannot take are dropped there, not here.
13
19
  */
14
20
  export function resolveInvocableDispatcher(field, ctx, describe) {
21
+ // An injected instance carries the identity the kernel stamped at Phase 5, so
22
+ // it is never a declaration — handing one to `ensureKindRef` reads it as an
23
+ // inline declaration missing its `kind`, a message pointing at nothing the
24
+ // author wrote.
25
+ const injected = field !== null && typeof field === "object" ? getRefIdentity(field) : undefined;
26
+ if (injected && !isExecutableInstance(field)) {
27
+ throw new RuntimeError("ERR_REF_UNRESOLVED", `${describe()}: 'invoke' references '${injected.name}' (${injected.kind}), which has ` +
28
+ `neither invoke() nor run() and cannot be dispatched. Reference an invocable or ` +
29
+ `runnable resource.`);
30
+ }
15
31
  // A `!ref` inside an `x-telo-scope` array is never rewritten by Phase 2.5, so it
16
32
  // arrives as the raw sentinel — which has no `name` and would otherwise fail with
17
33
  // a message pointing nowhere. `ensureKindRef` is the same rescue `ctx.resolveRef`
18
34
  // performs; both resolution paths have to normalize, or a slot works only
19
35
  // depending on which one its kind happens to use.
20
- const normalized = ctx.ensureKindRef && field !== null && typeof field === "object" && !isInvocableInstance(field)
36
+ const normalized = ctx.ensureKindRef &&
37
+ !injected &&
38
+ field !== null &&
39
+ typeof field === "object" &&
40
+ !isExecutableInstance(field)
21
41
  ? ctx.ensureKindRef(field)
22
42
  : field;
23
- const target = resolveRefInstance(normalized, ctx, isInvocableInstance, () => `${describe()}: 'invoke'`, "Telo.Invocable");
43
+ const target = resolveRefInstance(normalized, ctx, isExecutableInstance, () => `${describe()}: 'invoke'`, "Telo.Executable");
24
44
  // Dispatch through the traced chokepoint needs the target's kind+name: from
25
45
  // the `!ref` identity the kernel stamped at injection, else from the ref.
26
46
  const id = getRefIdentity(target) ?? normalized;
27
47
  if (!id || typeof id.kind !== "string" || typeof id.name !== "string") {
28
- return (inputs, invokeCtx) => target.invoke(inputs, invokeCtx);
48
+ return async (inputs, invokeCtx) => typeof target.invoke === "function"
49
+ ? target.invoke(inputs, invokeCtx)
50
+ : target.run(invokeCtx);
29
51
  }
30
52
  const { kind, name } = id;
31
53
  return (inputs, invokeCtx) => ctx.invokeResolved(kind, name, target, inputs, invokeCtx);
32
54
  }
33
- function isInvocableInstance(value) {
34
- return typeof value?.invoke === "function";
55
+ function isExecutableInstance(value) {
56
+ const candidate = value;
57
+ return typeof candidate?.invoke === "function" || typeof candidate?.run === "function";
35
58
  }
@@ -331,6 +331,26 @@ export interface ResourceContext extends ControllerContext {
331
331
  * access — a module whose files are never read never downloads them.
332
332
  */
333
333
  resolveModuleFile(relative: string): Promise<string>;
334
+ /**
335
+ * Resolve a platform-specific file by the logical `name` a `native:` entry
336
+ * declares, and return it as a `file://` **URI** — convert with
337
+ * `fileURLToPath` for an API that takes a path.
338
+ *
339
+ * Resolved against the module that declares the controller this resource runs
340
+ * — the module declaring its kind, or the ancestor a concrete-`extends` kind
341
+ * inherits its controller from — never the module that declared the resource:
342
+ * the file ships with the code asking for it. The first entry of that name, in
343
+ * declaration order, whose platform tuple matches the host wins.
344
+ *
345
+ * Rejects with `ERR_NATIVE_FILE_UNAVAILABLE` when the module declares no such
346
+ * name, when no entry matches the host (naming the host tuple and every tuple
347
+ * shipped), or when a source checkout's staged file is missing or does not
348
+ * match its pin. A staged file is never fetched here.
349
+ *
350
+ * Asynchronous because a published module's native layer is fetched on first
351
+ * use.
352
+ */
353
+ resolveNativeFile(name: string): Promise<string>;
334
354
  /** Load a single module (its own file + `include`d partials). Use this when
335
355
  * you need just the declaring file's manifests. */
336
356
  loadModule(url: string, options?: LoadOptions): Promise<ResourceManifest[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"resource-context.d.ts","sourceRoot":"","sources":["../src/resource-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resource-context.d.ts","sourceRoot":"","sources":["../src/resource-context.ts"],"names":[],"mappings":"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"}
@@ -100,7 +100,10 @@ export interface SequenceError {
100
100
  * casing subtly wrong, or collide with the fourth.
101
101
  */
102
102
  export interface StepBodyOwner {
103
- /** The owning kind's suffix (`Sequence`, `Iteration`, `Transaction`). */
103
+ /** The owning kind's `metadata.name`, exactly (`Sequence`, `Iteration`,
104
+ * `Workflow`). The load pass derives the same value from the definition, so
105
+ * any other string gives a loaded body's targets different names — and a
106
+ * target's name is its durable identity. */
104
107
  kind: string;
105
108
  /** The owning resource's `metadata.name`. */
106
109
  resourceName: string;
@@ -111,10 +114,17 @@ export interface StepBodyOwner {
111
114
  * `previous`, …) through `extraCtx`; the engine knows none of them. */
112
115
  export declare class StepEngine {
113
116
  private readonly ctx;
114
- /** Prefix for generated inline-invoke resource names; unique per host resource
115
- * (`SequenceMySeq`, `LoopPollUntilReady`). */
116
- private readonly namePrefix;
117
+ private readonly owner;
117
118
  constructor(ctx: StepEngineContext, owner: StepBodyOwner);
119
+ /**
120
+ * Turn every inline `invoke:` in a step list into a registered, named resource.
121
+ *
122
+ * A manifest reaches a controller with every inline step target already
123
+ * extracted at load under {@link inlineStepTargetName}, so there each target is
124
+ * a `{kind, name}` reference and `ensureKindRef` returns it unchanged. What this
125
+ * still names is a body assembled at runtime — a template body's children and
126
+ * steps built in code — which never passes through load.
127
+ */
118
128
  resolveInvokes(stepList: Step[], path?: string[]): void;
119
129
  private inlineInvokeResourceName;
120
130
  /**
@@ -163,8 +173,54 @@ export declare class StepEngine {
163
173
  private executeThrowStep;
164
174
  private executeTryStep;
165
175
  }
176
+ /**
177
+ * The name an inline step target is registered under: the owner's kind and name,
178
+ * the step's path through the body (`["steps", "1", "then", "0"]`), then the
179
+ * step's own name, each PascalCased and concatenated.
180
+ *
181
+ * ONE rule, because the name is durable identity — a journal records a step's
182
+ * target by kind, name and module, and a replay that reaches a different name
183
+ * refuses the run. The load pass extracts inline targets under it and
184
+ * {@link StepEngine.resolveInvokes} names runtime-assembled ones under it; two
185
+ * spellings would eventually disagree.
186
+ *
187
+ * Only the alphanumeric runs of each segment survive, so the result does not
188
+ * depend on how a caller split the path at punctuation (a case key `v1.0` and
189
+ * the two segments `v1`, `0` name the same step).
190
+ */
191
+ export declare function inlineStepTargetName(owner: StepBodyOwner, stepPath: readonly string[], stepName: string): string;
166
192
  /** Normalize any caught failure to the `error` shape a `catch:` branch reads.
167
193
  * Shared with the composers' whole-operation `catches:`, so one caught failure
168
194
  * has one shape wherever it is read. */
169
195
  export declare function toSequenceError(err: unknown, stepName: string): SequenceError;
196
+ /**
197
+ * Where a step list's journal keys hang from.
198
+ *
199
+ * At the top of a durable run there is no ambient path and the base is `steps`.
200
+ * Inside one, it is the path of the step that dispatched this body — so a nested
201
+ * sequence's `work` becomes `steps/importAll/work` rather than a second
202
+ * `steps/work`, and two nested bodies can no longer collide.
203
+ *
204
+ * The dispatching step's path is used directly rather than with a `steps`
205
+ * segment appended: the parent path already names one dispatch site, and every
206
+ * other segment the grammar produces (`then`, `do[2]`, `cases/x`) is distinct
207
+ * from a step name, so nothing else can generate the same key.
208
+ */
209
+ export declare function baseStepPath(invokeCtx?: InvokeContext): string;
210
+ /**
211
+ * The journal prefix for ONE turn of a composer that runs its body repeatedly —
212
+ * an iteration's item, a loop's turn, a projection's element.
213
+ *
214
+ * A composer that runs its body N times and journals every turn under the SAME
215
+ * prefix is not merely imprecise: the journal takes the first writer at a key,
216
+ * so turns 2..N replay turn 1's recorded outcome instead of executing. The work
217
+ * is silently skipped and the run still completes. The engine's own `while`
218
+ * already qualifies each turn this way (`stepPath(path, "do", turn)`); a
219
+ * controller driving the body itself has to do the same, and this is that
220
+ * prefix so the three of them cannot spell it differently.
221
+ *
222
+ * The index is the turn's position, which is stable across a replay because the
223
+ * collection it indexes is derived from values the run has already journaled.
224
+ */
225
+ export declare function turnStepPath(invokeCtx: InvokeContext | undefined, turn: number): string;
170
226
  //# sourceMappingURL=step-engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"step-engine.d.ts","sourceRoot":"","sources":["../src/step-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"step-engine.d.ts","sourceRoot":"","sources":["../src/step-engine.ts"],"names":[],"mappings":"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"}
@@ -56,13 +56,20 @@ function isValueStep(step) {
56
56
  * `previous`, …) through `extraCtx`; the engine knows none of them. */
57
57
  export class StepEngine {
58
58
  ctx;
59
- /** Prefix for generated inline-invoke resource names; unique per host resource
60
- * (`SequenceMySeq`, `LoopPollUntilReady`). */
61
- namePrefix;
59
+ owner;
62
60
  constructor(ctx, owner) {
63
61
  this.ctx = ctx;
64
- this.namePrefix = `${pascalCase(owner.kind)}${pascalCase(owner.resourceName)}`;
62
+ this.owner = owner;
65
63
  }
64
+ /**
65
+ * Turn every inline `invoke:` in a step list into a registered, named resource.
66
+ *
67
+ * A manifest reaches a controller with every inline step target already
68
+ * extracted at load under {@link inlineStepTargetName}, so there each target is
69
+ * a `{kind, name}` reference and `ensureKindRef` returns it unchanged. What this
70
+ * still names is a body assembled at runtime — a template body's children and
71
+ * steps built in code — which never passes through load.
72
+ */
66
73
  resolveInvokes(stepList, path = ["steps"]) {
67
74
  for (const [index, step] of stepList.entries()) {
68
75
  const stepPath = [...path, String(index)];
@@ -101,9 +108,7 @@ export class StepEngine {
101
108
  }
102
109
  }
103
110
  inlineInvokeResourceName(stepName, stepPath) {
104
- const path = stepPath.map(pascalCase).join("");
105
- const step = pascalCase(stepName);
106
- return `${this.namePrefix}${path}${step}`;
111
+ return inlineStepTargetName(this.owner, stepPath, stepName);
107
112
  }
108
113
  /**
109
114
  * @param path Journal key prefix for this list — see {@link stepPath}. A
@@ -323,9 +328,28 @@ export class StepEngine {
323
328
  }
324
329
  }
325
330
  }
326
- /** The naming recipe for a generated inline-invoke resource. Module-private: it
327
- * is the engine's own, and a bare `pascalCase` on the SDK's flat surface is a
328
- * utility nobody should be reimplementing a name from. */
331
+ /**
332
+ * The name an inline step target is registered under: the owner's kind and name,
333
+ * the step's path through the body (`["steps", "1", "then", "0"]`), then the
334
+ * step's own name, each PascalCased and concatenated.
335
+ *
336
+ * ONE rule, because the name is durable identity — a journal records a step's
337
+ * target by kind, name and module, and a replay that reaches a different name
338
+ * refuses the run. The load pass extracts inline targets under it and
339
+ * {@link StepEngine.resolveInvokes} names runtime-assembled ones under it; two
340
+ * spellings would eventually disagree.
341
+ *
342
+ * Only the alphanumeric runs of each segment survive, so the result does not
343
+ * depend on how a caller split the path at punctuation (a case key `v1.0` and
344
+ * the two segments `v1`, `0` name the same step).
345
+ */
346
+ export function inlineStepTargetName(owner, stepPath, stepName) {
347
+ const path = stepPath.map(pascalCase).join("");
348
+ return `${pascalCase(owner.kind)}${pascalCase(owner.resourceName)}${path}${pascalCase(stepName)}`;
349
+ }
350
+ /** The casing half of {@link inlineStepTargetName}. Module-private: a bare
351
+ * `pascalCase` on the SDK's flat surface is a utility nobody should be
352
+ * reimplementing a name from. */
329
353
  function pascalCase(s) {
330
354
  return s
331
355
  .split(/[^a-zA-Z0-9]+/)
@@ -360,6 +384,24 @@ export function toSequenceError(err, stepName) {
360
384
  * other segment the grammar produces (`then`, `do[2]`, `cases/x`) is distinct
361
385
  * from a step name, so nothing else can generate the same key.
362
386
  */
363
- function baseStepPath(invokeCtx) {
387
+ export function baseStepPath(invokeCtx) {
364
388
  return invokeCtx?.durablePath ?? "steps";
365
389
  }
390
+ /**
391
+ * The journal prefix for ONE turn of a composer that runs its body repeatedly —
392
+ * an iteration's item, a loop's turn, a projection's element.
393
+ *
394
+ * A composer that runs its body N times and journals every turn under the SAME
395
+ * prefix is not merely imprecise: the journal takes the first writer at a key,
396
+ * so turns 2..N replay turn 1's recorded outcome instead of executing. The work
397
+ * is silently skipped and the run still completes. The engine's own `while`
398
+ * already qualifies each turn this way (`stepPath(path, "do", turn)`); a
399
+ * controller driving the body itself has to do the same, and this is that
400
+ * prefix so the three of them cannot spell it differently.
401
+ *
402
+ * The index is the turn's position, which is stable across a replay because the
403
+ * collection it indexes is derived from values the run has already journaled.
404
+ */
405
+ export function turnStepPath(invokeCtx, turn) {
406
+ return stepPath(baseStepPath(invokeCtx), turn);
407
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/sdk",
3
- "version": "0.86.0",
3
+ "version": "0.90.0",
4
4
  "description": "Telo SDK - Public API for Telo module authors.",
5
5
  "keywords": [
6
6
  "telo",
@@ -1,9 +1,11 @@
1
1
  import type { InvokeContext } from "./cancellation.js";
2
2
  import type { Invocable } from "./capabilities/invokable.js";
3
+ import type { Runnable } from "./capabilities/runnable.js";
3
4
  import type { ModuleContext } from "./module-context.js";
4
5
  import type { KindRef } from "./ref.js";
5
6
  import { resolveRefInstance, type RefResolveContext } from "./resolve-ref-instance.js";
6
7
  import { getRefIdentity, type ResourceInstance } from "./resource-instance.js";
8
+ import { RuntimeError } from "./types.js";
7
9
 
8
10
  /** The context a decorator kind composes to dispatch its wrapped target. */
9
11
  export interface DispatchContext extends RefResolveContext {
@@ -25,8 +27,10 @@ export interface DispatchContext extends RefResolveContext {
25
27
  ensureKindRef?(value: unknown): KindRef;
26
28
  }
27
29
 
30
+ type ExecutableInstance = ResourceInstance & (Invocable | Runnable);
31
+
28
32
  /**
29
- * Resolve a decorator's `invoke:` field to a live invocable and return a thunk
33
+ * Resolve a decorator's `invoke:` field to a live executable and return a thunk
30
34
  * that dispatches it through the traced chokepoint. The field is either a
31
35
  * Phase-5-injected instance or a raw `{ kind, name, alias }` ref resolved
32
36
  * against the module context. Resolution is eager (fail-fast on a bad ref);
@@ -35,38 +39,65 @@ export interface DispatchContext extends RefResolveContext {
35
39
  * The thunk's optional second argument seeds the dispatch's {@link InvokeContext}
36
40
  * (e.g. a decorator-owned cancellation scope); when omitted the ambient
37
41
  * invocation context applies unchanged.
42
+ *
43
+ * The target is anything a step's `invoke:` accepts: an instance with `invoke()`
44
+ * or, run-only, with `run()`. Both go to `invokeResolved`, which calls `run()`
45
+ * when there is no `invoke()` — so a run-only target is started exactly as a
46
+ * step starts it, and the inputs it cannot take are dropped there, not here.
38
47
  */
39
48
  export function resolveInvocableDispatcher(
40
49
  field: unknown,
41
50
  ctx: DispatchContext,
42
51
  describe: () => string,
43
52
  ): (inputs: Record<string, unknown>, invokeCtx?: InvokeContext) => Promise<unknown> {
53
+ // An injected instance carries the identity the kernel stamped at Phase 5, so
54
+ // it is never a declaration — handing one to `ensureKindRef` reads it as an
55
+ // inline declaration missing its `kind`, a message pointing at nothing the
56
+ // author wrote.
57
+ const injected =
58
+ field !== null && typeof field === "object" ? getRefIdentity(field) : undefined;
59
+ if (injected && !isExecutableInstance(field)) {
60
+ throw new RuntimeError(
61
+ "ERR_REF_UNRESOLVED",
62
+ `${describe()}: 'invoke' references '${injected.name}' (${injected.kind}), which has ` +
63
+ `neither invoke() nor run() and cannot be dispatched. Reference an invocable or ` +
64
+ `runnable resource.`,
65
+ );
66
+ }
44
67
  // A `!ref` inside an `x-telo-scope` array is never rewritten by Phase 2.5, so it
45
68
  // arrives as the raw sentinel — which has no `name` and would otherwise fail with
46
69
  // a message pointing nowhere. `ensureKindRef` is the same rescue `ctx.resolveRef`
47
70
  // performs; both resolution paths have to normalize, or a slot works only
48
71
  // depending on which one its kind happens to use.
49
72
  const normalized =
50
- ctx.ensureKindRef && field !== null && typeof field === "object" && !isInvocableInstance(field)
73
+ ctx.ensureKindRef &&
74
+ !injected &&
75
+ field !== null &&
76
+ typeof field === "object" &&
77
+ !isExecutableInstance(field)
51
78
  ? ctx.ensureKindRef(field)
52
79
  : field;
53
80
  const target = resolveRefInstance(
54
81
  normalized,
55
82
  ctx,
56
- isInvocableInstance,
83
+ isExecutableInstance,
57
84
  () => `${describe()}: 'invoke'`,
58
- "Telo.Invocable",
85
+ "Telo.Executable",
59
86
  );
60
87
  // Dispatch through the traced chokepoint needs the target's kind+name: from
61
88
  // the `!ref` identity the kernel stamped at injection, else from the ref.
62
89
  const id = getRefIdentity(target as object) ?? (normalized as Partial<KindRef> | undefined);
63
90
  if (!id || typeof id.kind !== "string" || typeof id.name !== "string") {
64
- return (inputs, invokeCtx) => target.invoke(inputs, invokeCtx);
91
+ return async (inputs, invokeCtx) =>
92
+ typeof (target as Partial<Invocable>).invoke === "function"
93
+ ? (target as Invocable).invoke(inputs, invokeCtx)
94
+ : (target as Runnable).run(invokeCtx);
65
95
  }
66
96
  const { kind, name } = id;
67
97
  return (inputs, invokeCtx) => ctx.invokeResolved(kind, name, target, inputs, invokeCtx);
68
98
  }
69
99
 
70
- function isInvocableInstance(value: unknown): value is ResourceInstance & Invocable {
71
- return typeof (value as Invocable | undefined)?.invoke === "function";
100
+ function isExecutableInstance(value: unknown): value is ExecutableInstance {
101
+ const candidate = value as Partial<Invocable & Runnable> | undefined;
102
+ return typeof candidate?.invoke === "function" || typeof candidate?.run === "function";
72
103
  }
@@ -362,6 +362,26 @@ export interface ResourceContext extends ControllerContext {
362
362
  * access — a module whose files are never read never downloads them.
363
363
  */
364
364
  resolveModuleFile(relative: string): Promise<string>;
365
+ /**
366
+ * Resolve a platform-specific file by the logical `name` a `native:` entry
367
+ * declares, and return it as a `file://` **URI** — convert with
368
+ * `fileURLToPath` for an API that takes a path.
369
+ *
370
+ * Resolved against the module that declares the controller this resource runs
371
+ * — the module declaring its kind, or the ancestor a concrete-`extends` kind
372
+ * inherits its controller from — never the module that declared the resource:
373
+ * the file ships with the code asking for it. The first entry of that name, in
374
+ * declaration order, whose platform tuple matches the host wins.
375
+ *
376
+ * Rejects with `ERR_NATIVE_FILE_UNAVAILABLE` when the module declares no such
377
+ * name, when no entry matches the host (naming the host tuple and every tuple
378
+ * shipped), or when a source checkout's staged file is missing or does not
379
+ * match its pin. A staged file is never fetched here.
380
+ *
381
+ * Asynchronous because a published module's native layer is fetched on first
382
+ * use.
383
+ */
384
+ resolveNativeFile(name: string): Promise<string>;
365
385
  /** Load a single module (its own file + `include`d partials). Use this when
366
386
  * you need just the declaring file's manifests. */
367
387
  loadModule(url: string, options?: LoadOptions): Promise<ResourceManifest[]>;
@@ -151,7 +151,10 @@ function isValueStep(step: Step): step is ValueStep {
151
151
  * casing subtly wrong, or collide with the fourth.
152
152
  */
153
153
  export interface StepBodyOwner {
154
- /** The owning kind's suffix (`Sequence`, `Iteration`, `Transaction`). */
154
+ /** The owning kind's `metadata.name`, exactly (`Sequence`, `Iteration`,
155
+ * `Workflow`). The load pass derives the same value from the definition, so
156
+ * any other string gives a loaded body's targets different names — and a
157
+ * target's name is its durable identity. */
155
158
  kind: string;
156
159
  /** The owning resource's `metadata.name`. */
157
160
  resourceName: string;
@@ -162,17 +165,20 @@ export interface StepBodyOwner {
162
165
  * kind injects its own scope variables (`item`, `index`, `iteration`,
163
166
  * `previous`, …) through `extraCtx`; the engine knows none of them. */
164
167
  export class StepEngine {
165
- /** Prefix for generated inline-invoke resource names; unique per host resource
166
- * (`SequenceMySeq`, `LoopPollUntilReady`). */
167
- private readonly namePrefix: string;
168
-
169
168
  constructor(
170
169
  private readonly ctx: StepEngineContext,
171
- owner: StepBodyOwner,
172
- ) {
173
- this.namePrefix = `${pascalCase(owner.kind)}${pascalCase(owner.resourceName)}`;
174
- }
170
+ private readonly owner: StepBodyOwner,
171
+ ) {}
175
172
 
173
+ /**
174
+ * Turn every inline `invoke:` in a step list into a registered, named resource.
175
+ *
176
+ * A manifest reaches a controller with every inline step target already
177
+ * extracted at load under {@link inlineStepTargetName}, so there each target is
178
+ * a `{kind, name}` reference and `ensureKindRef` returns it unchanged. What this
179
+ * still names is a body assembled at runtime — a template body's children and
180
+ * steps built in code — which never passes through load.
181
+ */
176
182
  resolveInvokes(stepList: Step[], path: string[] = ["steps"]): void {
177
183
  for (const [index, step] of stepList.entries()) {
178
184
  const stepPath = [...path, String(index)];
@@ -210,9 +216,7 @@ export class StepEngine {
210
216
  }
211
217
 
212
218
  private inlineInvokeResourceName(stepName: string, stepPath: string[]): string {
213
- const path = stepPath.map(pascalCase).join("");
214
- const step = pascalCase(stepName);
215
- return `${this.namePrefix}${path}${step}`;
219
+ return inlineStepTargetName(this.owner, stepPath, stepName);
216
220
  }
217
221
 
218
222
  /**
@@ -583,9 +587,33 @@ export class StepEngine {
583
587
  }
584
588
 
585
589
 
586
- /** The naming recipe for a generated inline-invoke resource. Module-private: it
587
- * is the engine's own, and a bare `pascalCase` on the SDK's flat surface is a
588
- * utility nobody should be reimplementing a name from. */
590
+ /**
591
+ * The name an inline step target is registered under: the owner's kind and name,
592
+ * the step's path through the body (`["steps", "1", "then", "0"]`), then the
593
+ * step's own name, each PascalCased and concatenated.
594
+ *
595
+ * ONE rule, because the name is durable identity — a journal records a step's
596
+ * target by kind, name and module, and a replay that reaches a different name
597
+ * refuses the run. The load pass extracts inline targets under it and
598
+ * {@link StepEngine.resolveInvokes} names runtime-assembled ones under it; two
599
+ * spellings would eventually disagree.
600
+ *
601
+ * Only the alphanumeric runs of each segment survive, so the result does not
602
+ * depend on how a caller split the path at punctuation (a case key `v1.0` and
603
+ * the two segments `v1`, `0` name the same step).
604
+ */
605
+ export function inlineStepTargetName(
606
+ owner: StepBodyOwner,
607
+ stepPath: readonly string[],
608
+ stepName: string,
609
+ ): string {
610
+ const path = stepPath.map(pascalCase).join("");
611
+ return `${pascalCase(owner.kind)}${pascalCase(owner.resourceName)}${path}${pascalCase(stepName)}`;
612
+ }
613
+
614
+ /** The casing half of {@link inlineStepTargetName}. Module-private: a bare
615
+ * `pascalCase` on the SDK's flat surface is a utility nobody should be
616
+ * reimplementing a name from. */
589
617
  function pascalCase(s: string): string {
590
618
  return s
591
619
  .split(/[^a-zA-Z0-9]+/)
@@ -622,6 +650,25 @@ export function toSequenceError(err: unknown, stepName: string): SequenceError {
622
650
  * other segment the grammar produces (`then`, `do[2]`, `cases/x`) is distinct
623
651
  * from a step name, so nothing else can generate the same key.
624
652
  */
625
- function baseStepPath(invokeCtx?: InvokeContext): string {
653
+ export function baseStepPath(invokeCtx?: InvokeContext): string {
626
654
  return invokeCtx?.durablePath ?? "steps";
627
655
  }
656
+
657
+ /**
658
+ * The journal prefix for ONE turn of a composer that runs its body repeatedly —
659
+ * an iteration's item, a loop's turn, a projection's element.
660
+ *
661
+ * A composer that runs its body N times and journals every turn under the SAME
662
+ * prefix is not merely imprecise: the journal takes the first writer at a key,
663
+ * so turns 2..N replay turn 1's recorded outcome instead of executing. The work
664
+ * is silently skipped and the run still completes. The engine's own `while`
665
+ * already qualifies each turn this way (`stepPath(path, "do", turn)`); a
666
+ * controller driving the body itself has to do the same, and this is that
667
+ * prefix so the three of them cannot spell it differently.
668
+ *
669
+ * The index is the turn's position, which is stable across a replay because the
670
+ * collection it indexes is derived from values the run has already journaled.
671
+ */
672
+ export function turnStepPath(invokeCtx: InvokeContext | undefined, turn: number): string {
673
+ return stepPath(baseStepPath(invokeCtx), turn);
674
+ }