fyflow-orchestration 0.7.0 → 0.8.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/AGENTS.md +1800 -200
- package/README.md +88 -104
- package/dist/browser/chunks/{chunk-YVOP3DIN.js → chunk-EUU44PHD.js} +2104 -283
- package/dist/browser/index.js +19 -9
- package/dist/browser/scheduler/index.js +101 -58
- package/dist/node/chunks/{chunk-YVOP3DIN.js → chunk-EUU44PHD.js} +2104 -283
- package/dist/node/index.js +19 -9
- package/dist/node/scheduler/index.js +101 -58
- package/dist/types/src/definition/assist.d.ts +29 -5
- package/dist/types/src/definition/condition.d.ts +49 -0
- package/dist/types/src/definition/regions.d.ts +12 -1
- package/dist/types/src/definition/registry.d.ts +52 -10
- package/dist/types/src/definition/schema.d.ts +20 -8
- package/dist/types/src/definition/types.d.ts +152 -23
- package/dist/types/src/definition/validate.d.ts +68 -20
- package/dist/types/src/definition/wiring.d.ts +58 -10
- package/dist/types/src/definition/witness.d.ts +12 -4
- package/dist/types/src/driver/driver.d.ts +772 -40
- package/dist/types/src/driver/listener.d.ts +7 -1
- package/dist/types/src/driver/log.d.ts +20 -5
- package/dist/types/src/driver/routing.d.ts +10 -5
- package/dist/types/src/fold/policies.d.ts +4 -5
- package/dist/types/src/fold/run-state.d.ts +245 -14
- package/dist/types/src/scheduler/bootstrap.d.ts +18 -26
- package/dist/types/src/scheduler/envelope-worker.d.ts +6 -5
- package/dist/types/src/scheduler/index.d.ts +2 -2
- package/dist/types/src/scheduler/runtime.d.ts +105 -32
- package/package.json +3 -3
|
@@ -231,6 +231,17 @@ export declare function branchPathOf(regions: RegionSets[], nodeId: string, item
|
|
|
231
231
|
* does.
|
|
232
232
|
*/
|
|
233
233
|
export declare function regionChainOf(regions: RegionSets[], nodeId: string): string[];
|
|
234
|
+
/**
|
|
235
|
+
* **The map instance a node is IN — the innermost `map` region containing it as a MEMBER** —
|
|
236
|
+
* `spec/flow-definition.md` v0.45, P38 (c), [ADR 0118](../../doc/decisions/0118-a-map-instance-keeps-its-item-while-a-node-of-it-may-still-be-entered.md).
|
|
237
|
+
* What `"$item"` names: the item of the instance this node is entered in. **The region chain's own walk**
|
|
238
|
+
* (`regionChainOf`), read innermost-first for the first region a `map` opened — so a node in a `fanout`
|
|
239
|
+
* nested inside a map instance names the MAP's item, and a `map` NODE names its ENCLOSING instance's item,
|
|
240
|
+
* because an opener is never a member of the region it opens (its branch cannot reach it, `FD-V10`).
|
|
241
|
+
* `undefined` for a node no map region contains — `FD-V49`'s refusal, and the one answer the validator,
|
|
242
|
+
* the driver and the wiring check all read from here, so the three cannot disagree about which item it is.
|
|
243
|
+
*/
|
|
244
|
+
export declare function innermostMapOf(regions: RegionSets[], nodeId: string): RegionSets | undefined;
|
|
234
245
|
/**
|
|
235
246
|
* **How many leading `branchPath` segments the two nodes have anything to compare
|
|
236
247
|
* on** — the length of the COMMON PREFIX of their two region chains, and the whole
|
|
@@ -327,7 +338,7 @@ export declare function branchIndexOf(regions: RegionSets[], nodeId: string): nu
|
|
|
327
338
|
*
|
|
328
339
|
* | out-arcs of | are | because |
|
|
329
340
|
* |---|---|---|
|
|
330
|
-
* | a `task`'s `edges` | **disjunctive** — exactly one is taken | section 3's routing rule 2 |
|
|
341
|
+
* | a `task`'s `edges`, and — v0.42 — an `ask`'s | **disjunctive** — exactly one is taken | section 3's routing rule 2; an ask routes as a task's settlement does (P35 (h)) |
|
|
331
342
|
* | a `fanout`'s `branches`, a `map`'s `branch` | **conjunctive** — all are entered | `JP-R5`, which emits every `branch.opened` before any dispatch |
|
|
332
343
|
*
|
|
333
344
|
* So a branch entry never *dominates* its own join — every path to the join goes
|
|
@@ -79,14 +79,20 @@ export declare class UndeclaredKey extends RegistryError {
|
|
|
79
79
|
/** A predicate or language the document NAMES that `code` did not supply, or a group a type names that the document lacks. */
|
|
80
80
|
export declare class NameMissing extends RegistryError {
|
|
81
81
|
}
|
|
82
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* A derivation returned something that is not a `PoolSpec`, threw, or produced a pool the runtime refuses: a resident group
|
|
84
|
+
* beside `idleTimeout: 0`, or — since v0.39 ([Q619](../../doc/questions/q619.md) option B) — a group of the built-in
|
|
85
|
+
* `KeyedRateLimitGroup` type held in `residentGroups`, which the scheduler would count in one `""` bucket.
|
|
86
|
+
*/
|
|
83
87
|
export declare class DerivationRefused extends RegistryError {
|
|
84
88
|
}
|
|
85
89
|
/**
|
|
86
90
|
* **A registered GATE type is not a `GateType`** — v0.23 (W92, ADR 0066): not an object; a key beside the
|
|
87
|
-
* interface's
|
|
88
|
-
*
|
|
89
|
-
*
|
|
91
|
+
* interface's seven; **static routes AND `routesFor`, or neither** (v0.30, ADR 0092); a `routesFor` or a
|
|
92
|
+
* `settingsProblem` that is not a function (v0.30); `routes` empty, repeated or outside `FD-V16`'s charset; a
|
|
93
|
+
* `defaultRoute` that is not one of them; a `settingsSchema` outside the subset; a `keyResolvedRoutes` that is not
|
|
94
|
+
* an array of its own routes, or repeats one (v0.25); or no `fn`. What a derived type's `routesFor` RETURNS is
|
|
95
|
+
* held at the gate, `FD-V39`, since only a gate has settings. `gateTypeProblem` is the predicate, shared with
|
|
90
96
|
* `FD-V39`'s second clause, so the registry and the validator cannot disagree about what a gate type IS.
|
|
91
97
|
*/
|
|
92
98
|
export declare class GateTypeRefused extends RegistryError {
|
|
@@ -110,12 +116,21 @@ export declare const WORKER_KEYS: readonly string[];
|
|
|
110
116
|
export declare const CHECKED_WORKER_SCHEMAS: readonly string[];
|
|
111
117
|
/** A document node type's keys. */
|
|
112
118
|
export declare const NODE_TYPE_DECLARATION_KEYS: readonly string[];
|
|
113
|
-
/** A `PoolSpec`'s keys — what a derivation may return. */
|
|
119
|
+
/** A `PoolSpec`'s keys — what a derivation may return. `cancelGraceMs` and `messages` since v0.33 (P33 decision 6, W159). */
|
|
114
120
|
export declare const POOL_SPEC_KEYS: readonly string[];
|
|
115
|
-
/** A
|
|
121
|
+
/** A `PoolSpec.messages` object's keys — the scheduler's `MessageOptions`, v0.33. */
|
|
122
|
+
export declare const MESSAGE_OPTION_KEYS: readonly string[];
|
|
123
|
+
/** A document type's `pool` field: the `PoolSpec` minus what the type states beside it — and, since v0.37, a named instance's `pool` (ADR 0099). */
|
|
116
124
|
export declare const DECLARED_POOL_KEYS: readonly string[];
|
|
117
|
-
/** A
|
|
125
|
+
/** A GROUP instance's keys — and the two every instance shares. */
|
|
118
126
|
export declare const INSTANCE_KEYS: readonly string[];
|
|
127
|
+
/**
|
|
128
|
+
* **A POOL instance's keys: the two, and `pool`** — v0.37,
|
|
129
|
+
* [ADR 0099](../../doc/decisions/0099-a-named-instance-of-a-document-type-may-declare-its-own-pool-options.md),
|
|
130
|
+
* [W165](../../doc/work-items/w165-pool-options-on-a-named-pool-instance.md): the instance's OWN pool options, the
|
|
131
|
+
* `DECLARED_POOL_KEYS`, on an instance of a DOCUMENT type only. A group instance still declares the two alone.
|
|
132
|
+
*/
|
|
133
|
+
export declare const POOL_INSTANCE_KEYS: readonly string[];
|
|
119
134
|
/** A class-form entry is the one whose `pool` is a FUNCTION; a document form's `pool` is an options object or absent. */
|
|
120
135
|
export declare function isDerivation(t: NodeTypeEntry): t is NodeTypeDefinition;
|
|
121
136
|
/**
|
|
@@ -125,19 +140,38 @@ export declare function isDerivation(t: NodeTypeEntry): t is NodeTypeDefinition;
|
|
|
125
140
|
* deliberately not offered — a class is where any other rule lives.
|
|
126
141
|
*/
|
|
127
142
|
export declare function mergeConfig(base: unknown, over: unknown): unknown;
|
|
143
|
+
/** The pool options a document type declares, and since v0.37 a named instance of one (ADR 0099). */
|
|
144
|
+
type DeclaredPool = NonNullable<NodeTypeDeclaration['pool']>;
|
|
128
145
|
/**
|
|
129
146
|
* **The document form of a node type IS the identity derivation** — decision 2: `pool(config)`
|
|
130
147
|
* merges the instance's config over the declared one, and copies the declared pool fields and the
|
|
131
148
|
* declared groups. Keys are copied only when declared, so an absent `groups` stays absent (fact 5).
|
|
132
149
|
* The declaration's shape is checked by `resolveRegistry` before this is called; here it is trusted.
|
|
150
|
+
*
|
|
151
|
+
* **`over` is a NAMED INSTANCE's own pool options** (v0.37, ADR 0099 rules 1-3): merged over the declared `pool` by
|
|
152
|
+
* `mergePool`, and the result is what this derivation hands on. Absent — every type's default instance, and every
|
|
153
|
+
* instance that declares none — the derivation is the one it has always been, option for option (P18 fact 5).
|
|
133
154
|
*/
|
|
134
|
-
export declare function nodeTypeFromDeclaration(decl: NodeTypeDeclaration): NodeTypeDefinition;
|
|
155
|
+
export declare function nodeTypeFromDeclaration(decl: NodeTypeDeclaration, over?: DeclaredPool): NodeTypeDefinition;
|
|
135
156
|
/**
|
|
136
157
|
* **Why a derivation's output is not a `PoolSpec`, or `null`** — the check BOTH forms pass through
|
|
137
158
|
* (decision 2's *a class cannot compute around a check*). The scheduler coerces or ignores a wrong
|
|
138
159
|
* option in silence exactly as it does a retry policy (`FD-V30`'s measurements), so the shape is
|
|
139
160
|
* pinned here: numbers where numbers, a string list for `groups`, a string list or a `{ key: cost }`
|
|
140
|
-
* record for `residentGroups`, and no key beside the
|
|
161
|
+
* record for `residentGroups`, and no key beside the eight.
|
|
162
|
+
*
|
|
163
|
+
* **`cancelGraceMs` and `messages` (v0.33, P33 decision 6, W159) are held to the SCHEDULER's own rules**, read
|
|
164
|
+
* at the pin in its `validateGraceMs` and `resolveMessageOptions`, where it throws at `new WorkerManager`:
|
|
165
|
+
* `cancelGraceMs` a number `>= 0` — which `NaN` is not, so no clause of its own refuses it — and `Infinity` admitted, the scheduler's *never force*; `messages` a
|
|
166
|
+
* plain object of `flushIntervalMs` (finite, `> 0`) and `maxBuffered` (an integer `>= 1`), each optional. **A
|
|
167
|
+
* `messages` key that is PRESENT is held whatever its value**, `undefined` included, unlike the top-level keys
|
|
168
|
+
* here: the scheduler reads `cancelGraceMs ?? 2000` but spreads `messages` over its defaults, so a present
|
|
169
|
+
* `undefined` replaces a default and it throws. A key beside the two is refused, as everywhere in this module —
|
|
170
|
+
* and it is not merely ignored by the scheduler: the resolved object is carried to every worker, so on a
|
|
171
|
+
* THREADED pool a stray key holding a value that cannot be cloned fails the task at run time with *could not be
|
|
172
|
+
* cloned* (W159's conformity reader, F1). Refusing it here moves that failure to construction. **Stricter than
|
|
173
|
+
* the scheduler, where it is silent**: a `messages` that is not a plain object (it spreads one into its
|
|
174
|
+
* defaults and reads nothing), and a `cancelGraceMs` of `null` (it reads `?? 2000`), are refused here.
|
|
141
175
|
*/
|
|
142
176
|
export declare function poolSpecProblem(v: unknown): string | null;
|
|
143
177
|
/** The group keys a `PoolSpec` names, from both fields — what must exist in `groups`. */
|
|
@@ -160,8 +194,15 @@ export declare function poolOptionsOf(spec: PoolSpec, inline: boolean | undefine
|
|
|
160
194
|
* its output held to `PoolSpec`'s shape, the derived config against the WORKER's `configSchema`,
|
|
161
195
|
* every group it names present, and decision 9's refusal — a resident group beside `idleTimeout: 0`
|
|
162
196
|
* deadlocks a contended group (P18 fact 6, the scheduler reference's own sentence).
|
|
197
|
+
*
|
|
198
|
+
* **`pool` is a named instance's OWN pool options** (v0.37, ADR 0099): the instance is derived by its type's identity
|
|
199
|
+
* derivation with them merged over the type's declared ones (`nodeTypeFromDeclaration(declaration, pool)`), and the
|
|
200
|
+
* OUTPUT takes every check below exactly as any derivation's does — P37 decision 9's *through `derivePool`'s one check*.
|
|
201
|
+
* Its own shape, and its type being a DOCUMENT type, were held by the registry's shape check before this is called, on
|
|
202
|
+
* both roads. The returned `definition` is the TYPE's, as for every instance; `pool` is carried, copied, so a caller that
|
|
203
|
+
* hands the instance on (`createRuntime`, to the bootstrap helper) hands on what was resolved.
|
|
163
204
|
*/
|
|
164
|
-
export declare function derivePool(key: string, typeName: string, def: NodeTypeDefinition, worker: WorkerEntry | undefined, config: unknown, groupKeys: ReadonlySet<string>, refuse: new (at: string, m: string) => RegistryError): ResolvedPool;
|
|
205
|
+
export declare function derivePool(key: string, typeName: string, def: NodeTypeDefinition, worker: WorkerEntry | undefined, config: unknown, groupKeys: ReadonlySet<string>, refuse: new (at: string, m: string) => RegistryError, pool?: unknown): ResolvedPool;
|
|
165
206
|
export declare function checkRegistry(reg: {
|
|
166
207
|
workers?: Workers;
|
|
167
208
|
nodeTypes?: NodeTypes;
|
|
@@ -183,3 +224,4 @@ export declare function checkGateTypes(x: GateTypes | undefined): void;
|
|
|
183
224
|
* schemas, derived `PoolSpec`s and the adapters and factories as given.
|
|
184
225
|
*/
|
|
185
226
|
export declare function resolveRegistry(doc: RegistryDocument, code?: RegistryCode): ResolvedRegistry;
|
|
227
|
+
export {};
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* A worker entry in the registry document declares up to four schemas (`configSchema`,
|
|
9
9
|
* `settingsSchema`, `inputSchema`, `outputSchema`); a group type declares one; a node-type class may
|
|
10
|
-
* declare one.
|
|
10
|
+
* declare one; and since v0.42 an `ask` NODE in a flow may declare one, `answerSchema`, held to this subset
|
|
11
|
+
* by `schemaProblem` when the flow is validated (`FD-V48`, W179) rather than when a registry is built. A worker's first two, a group type's and a class's are CHECKED — at `createRuntime`
|
|
11
12
|
* and at `new Driver` — and a worker's last two are declared, carried, enforced on ONE value per run
|
|
12
13
|
* each since v0.21 (the entry payload at `start()`, a person's resolution at `resolve()` — `FD-R4`, W73),
|
|
13
14
|
* never per settlement, and since v0.20 confirmed on a run by `scripts/check-workers.mjs` (P19, whose name is *what a schema
|
|
@@ -22,8 +23,11 @@
|
|
|
22
23
|
* shape one layer up: a document that says one thing and a validator that checks another, at exit 0.
|
|
23
24
|
* The refusal names the keyword and the path, so a consumer meets a refusal rather than a pass, and
|
|
24
25
|
* prediction 4's reversal (a real worker needing a keyword outside the subset) is legible the day it
|
|
25
|
-
* happens.
|
|
26
|
-
*
|
|
26
|
+
* happens. **ANNOTATION keywords are inside it too** — `examples` (v0.20, ADR 0056) and, since v0.36,
|
|
27
|
+
* `title`, `description`, `readOnly` and `writeOnly`
|
|
28
|
+
* ([ADR 0098](../../doc/decisions/0098-four-annotations-join-the-schema-subset-and-constrain-nothing.md)) —
|
|
29
|
+
* each with its VALUE SHAPE checked and none read by a value check; every other annotation
|
|
30
|
+
* (`deprecated`, `$comment`, `default`, `format`, `$schema`, `$id`) is outside it and refused the same way.
|
|
27
31
|
*
|
|
28
32
|
* **What `type` means over JSON data.** `number` and `integer` admit FINITE numbers only: JSON text
|
|
29
33
|
* cannot carry `NaN` or an infinity, so a schema over JSON data has no reading of them but *not a
|
|
@@ -41,15 +45,15 @@
|
|
|
41
45
|
/** A JSON Schema in the subset — data, as everything in a registry document is. Checked by `schemaProblem`. */
|
|
42
46
|
export type JsonSchema = Readonly<Record<string, unknown>>;
|
|
43
47
|
/**
|
|
44
|
-
* **The subset, enumerated** — the
|
|
45
|
-
* the corpus's schemas
|
|
48
|
+
* **The subset, enumerated** — the CONSTRAINING keywords P18 fact 1 measured as covering the sample's
|
|
49
|
+
* and the corpus's schemas, **and the ANNOTATIONS**, first `examples` —
|
|
46
50
|
* [ADR 0056](../../doc/decisions/0056-an-example-is-an-annotation-validated-against-the-schema-it-sits-on.md),
|
|
47
51
|
* [W72](../../doc/work-items/w72-the-contract-an-example-beside-every-schema-and-a-worker-run-on-it.md),
|
|
48
52
|
* the plan's first deliberate extension of the subset. `spec/flow-definition.md` section 3's table
|
|
49
|
-
* names the same
|
|
50
|
-
* (rule 8 obligation (e)'s third shape — a list is a claim about another list).
|
|
53
|
+
* names the same keywords and marks which annotate, and `test/definition/schema.test.ts` compares the
|
|
54
|
+
* two both ways (rule 8 obligation (e)'s third shape — a list is a claim about another list).
|
|
51
55
|
*
|
|
52
|
-
* `examples` differs from the
|
|
56
|
+
* `examples` differs from the constraining keywords in ONE way, and the difference is the decision: it
|
|
53
57
|
* constrains NOTHING when a value is checked (`findings` never reads it) and is itself HELD to the
|
|
54
58
|
* schema it sits on at construction (`schemaProblem` runs `findings` over each declared example) —
|
|
55
59
|
* so a worker's declared example is a value the check-time tools may RUN the worker on, and an
|
|
@@ -59,6 +63,14 @@ export type JsonSchema = Readonly<Record<string, unknown>>;
|
|
|
59
63
|
* self-consistent. The rule is optional — an absent `examples` refuses nothing (the maintainer's
|
|
60
64
|
* choice, W72's stop-and-ask 1) — and an EMPTY one is refused, because a declared-and-empty list
|
|
61
65
|
* is the silent kind (`enum`'s own reason).
|
|
66
|
+
*
|
|
67
|
+
* **And the annotations of v0.36** — `title` and `description` (a string), `readOnly` and
|
|
68
|
+
* `writeOnly` (a boolean) —
|
|
69
|
+
* [ADR 0098](../../doc/decisions/0098-four-annotations-join-the-schema-subset-and-constrain-nothing.md),
|
|
70
|
+
* P37 decision 4. Their bar: *an annotation is admitted if it constrains nothing in JSON Schema itself
|
|
71
|
+
* and its value shape is checked*. `schemaProblem` checks the shape; `findings` reads none of them, so
|
|
72
|
+
* **`writeOnly` hides nothing and promises no redaction**, and `readOnly` refuses nothing. They are in
|
|
73
|
+
* THIS list rather than a second one, so the spec's table binds them as it binds every other keyword.
|
|
62
74
|
*/
|
|
63
75
|
export declare const SCHEMA_KEYWORDS: readonly string[];
|
|
64
76
|
/** The type names `type` may use — JSON Schema's seven, `integer` included. */
|
|
@@ -8,26 +8,42 @@
|
|
|
8
8
|
import type { ResourceGroup } from 'fyflow-scheduler';
|
|
9
9
|
import type { JsonSchema } from './schema.js';
|
|
10
10
|
export type { JsonSchema } from './schema.js';
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* The terminal states an edge may opt into. `user_action` is refused: it suspends (FD-V18). **And
|
|
13
|
+
* `cancelled` is refused too** — a cancel is the consumer's own act and halts the run rather than
|
|
14
|
+
* routing it ([ADR 0094](../../doc/decisions/0094-a-cancelled-task-is-a-terminal-state-that-routes-no-edge-and-ends-its-run-cancelled.md)
|
|
15
|
+
* rule 1), so `FD-V18` still admits exactly these two.
|
|
16
|
+
*/
|
|
12
17
|
export type RoutableState = 'done' | 'failed';
|
|
13
|
-
/**
|
|
14
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Every terminal state a scheduler task can reach. **Six library states, four terminal** — `cancelled`
|
|
20
|
+
* since the scheduler pin W157 moved to, which ends a task through `scheduler.cancel()` alone
|
|
21
|
+
* ([ADR 0094](../../doc/decisions/0094-a-cancelled-task-is-a-terminal-state-that-routes-no-edge-and-ends-its-run-cancelled.md),
|
|
22
|
+
* W158). **Widening this union is BREAKING for a consumer switching on it exhaustively**, on
|
|
23
|
+
* `resumed`'s and `gated`'s precedent: such a switch stops compiling, and one comparing strings does
|
|
24
|
+
* not notice.
|
|
25
|
+
*/
|
|
26
|
+
export type TerminalState = 'done' | 'failed' | 'user_action' | 'cancelled';
|
|
15
27
|
/**
|
|
16
28
|
* **A declared reference to something the run has produced** —
|
|
17
29
|
* `spec/flow-definition.md` section 3's `needs`, and
|
|
18
30
|
* [ADR 0040](../../doc/decisions/0040-what-a-node-can-reach-is-the-runs-own-outputs-and-a-node-id-names-them-relative-to-a-branch-path.md).
|
|
19
31
|
*
|
|
20
|
-
*
|
|
32
|
+
* Four forms, all of them data (ADR 0002 rule 1 — nothing here is a function and
|
|
21
33
|
* everything survives `JSON.parse(JSON.stringify(x))`):
|
|
22
34
|
*
|
|
23
35
|
* | | |
|
|
24
36
|
* |---|---|
|
|
25
|
-
* | `"."` | what this node would have received anyway — the ordinary edge's value, and for a `map` instance its own item (`JP-R11`).
|
|
37
|
+
* | `"."` | what this node would have received anyway — the ordinary edge's value, and for a `map` instance its own item (`JP-R11`). Outside `FD-V16`'s charset, so it can never collide with a node id |
|
|
38
|
+
* | `"$payload"` | **the value the RUN entered with** — what `start()` was handed, from any node and any edge (v0.44, [ADR 0117](../../doc/decisions/0117-a-reference-may-name-what-reached-the-run.md)). Always there, so no `?` and no array form. `$` is outside `FD-V16`'s charset, and the whole `$` prefix is reserved: `"$item"` — a map instance's item — is W191's, and any other `$` spelling is `FD-V26` |
|
|
26
39
|
* | `"score"` | that node's output **on this node's own branch path**. Exactly one, or the run stops (`FD-R3`) |
|
|
27
40
|
* | `["score"]` | that node's outputs as an **array**, in ascending segment-wise-numeric `branchPath` order. Legal only where the reader is outside a region containing the named node (`FD-V28`) |
|
|
28
41
|
*
|
|
29
42
|
* **The array form uses JSON's own array syntax rather than a sigil**, so the
|
|
30
|
-
* grammar
|
|
43
|
+
* grammar invents tokens only for what has no node id: `"."`, the `?` modifier
|
|
44
|
+
* (v0.13), and — v0.44 — the `$` prefix. *(This read *"exactly one invented token"*
|
|
45
|
+
* until v0.13 and stayed so until W190.)* A `string` covers every token, so the
|
|
46
|
+
* TYPE does not move; `referenceTarget`'s parse does.
|
|
31
47
|
*/
|
|
32
48
|
export type Reference = string | readonly [string];
|
|
33
49
|
/**
|
|
@@ -37,8 +53,9 @@ export type Reference = string | readonly [string];
|
|
|
37
53
|
* object this describes; a node that does not receives what section 3 says an
|
|
38
54
|
* ordinary edge carries, unchanged.
|
|
39
55
|
*
|
|
40
|
-
* Only a `task` and
|
|
41
|
-
* key on the other
|
|
56
|
+
* Only a `task`, a `map` and — since v0.42 — an `ask` may carry it: `FD-V17` already refuses an
|
|
57
|
+
* undeclared key on the other four kinds, so that clause needs no rule of its own. *(This read "the
|
|
58
|
+
* other three", stale since v0.23's `gate`.)*
|
|
42
59
|
*/
|
|
43
60
|
export type Needs = Readonly<Record<string, Reference>>;
|
|
44
61
|
/**
|
|
@@ -223,13 +240,7 @@ export type Workers = ReadonlyMap<string, WorkerEntry> | Readonly<Record<string,
|
|
|
223
240
|
* validator reads of one is its `type` (`FD-V38`); a `PoolInstance` and a resolved pool both fit.
|
|
224
241
|
* **Absent means EMPTY**; a type's DEFAULT instance is implicit and never listed here.
|
|
225
242
|
*/
|
|
226
|
-
export type Pools = ReadonlyMap<string,
|
|
227
|
-
readonly type: string;
|
|
228
|
-
readonly config?: unknown;
|
|
229
|
-
}> | Readonly<Record<string, {
|
|
230
|
-
readonly type: string;
|
|
231
|
-
readonly config?: unknown;
|
|
232
|
-
}>>;
|
|
243
|
+
export type Pools = ReadonlyMap<string, Readonly<PoolInstance>> | Readonly<Record<string, Readonly<PoolInstance>>>;
|
|
233
244
|
/**
|
|
234
245
|
* **A declared transform: a language NAME and an expression in it** — `spec/flow-definition.md`
|
|
235
246
|
* section 2's `transform` subsection (v0.18). Data, as everything in a definition is (ADR 0002
|
|
@@ -306,6 +317,25 @@ export interface PoolSpec {
|
|
|
306
317
|
groups?: readonly string[];
|
|
307
318
|
/** Group keys held for the WORKER's lifetime rather than per task, at a cost each — never beside `idleTimeout: 0` (decision 9). */
|
|
308
319
|
residentGroups?: readonly string[] | Readonly<Record<string, number>>;
|
|
320
|
+
/**
|
|
321
|
+
* **Threaded pools: the ms a cancelled task's worker gets to stop by itself before it is forced** — the
|
|
322
|
+
* scheduler's own option, declarable since `spec/flow-definition.md` v0.33 (P33 decision 6, W159). Zero or
|
|
323
|
+
* more, `Infinity` included (the scheduler's *never force*); accepted, and ignored by the scheduler, on an
|
|
324
|
+
* inline pool.
|
|
325
|
+
*/
|
|
326
|
+
cancelGraceMs?: number;
|
|
327
|
+
/**
|
|
328
|
+
* **The bounds on a worker's `context.emit()`** — the scheduler's `messages` option, declarable since v0.33
|
|
329
|
+
* (P33 decision 6, W159): events batched for up to `flushIntervalMs` (a finite number > 0), at most
|
|
330
|
+
* `maxBuffered` (an integer >= 1) per buffer between flushes. Each key optional; a key PRESENT is held to its
|
|
331
|
+
* rule whatever its value, `undefined` included, because the scheduler spreads this object over its defaults
|
|
332
|
+
* and a present `undefined` is what it throws on. Written out rather than imported from the scheduler, as
|
|
333
|
+
* `POOL_SPEC_KEYS` is a literal: a key the scheduler adds is admitted by a version of the spec, not by a bump.
|
|
334
|
+
*/
|
|
335
|
+
messages?: Readonly<{
|
|
336
|
+
flushIntervalMs?: number;
|
|
337
|
+
maxBuffered?: number;
|
|
338
|
+
}>;
|
|
309
339
|
}
|
|
310
340
|
/**
|
|
311
341
|
* **A node type as a DERIVATION from an instance's config to pool options** — decision 2, the CLASS
|
|
@@ -343,7 +373,8 @@ export interface NodeTypeDefinition {
|
|
|
343
373
|
* a worker entry; `inline` is the type's; `config` is the default instance's constructor argument;
|
|
344
374
|
* `pool` carries the declared pool options (a `PoolSpec` minus `config` and `groups`); `groups` are
|
|
345
375
|
* the pool's group keys; `retryPolicy` and `settings` are what the type declares FOR its nodes. An
|
|
346
|
-
* instance's `config` merges shallowly over `config
|
|
376
|
+
* instance's `config` merges shallowly over `config`, and since v0.37 a named instance's own `pool` merges shallowly
|
|
377
|
+
* over `pool` (ADR 0099); every other field is copied as declared, every object in it copied.
|
|
347
378
|
*/
|
|
348
379
|
export interface NodeTypeDeclaration {
|
|
349
380
|
/** As `NodeTypeDefinition.worker`: absent only on a built-in that only transforms (ADR 0075). */
|
|
@@ -363,6 +394,13 @@ export interface PoolInstance {
|
|
|
363
394
|
type: string;
|
|
364
395
|
/** The instance's config — the derivation's input, merged over the type's for a document type. */
|
|
365
396
|
config?: unknown;
|
|
397
|
+
/**
|
|
398
|
+
* **The instance's OWN pool options** — v0.37, [ADR 0099](../../doc/decisions/0099-a-named-instance-of-a-document-type-may-declare-its-own-pool-options.md):
|
|
399
|
+
* the keys a type's `pool` may declare, merged SHALLOWLY over its type's (the instance's key winning, a key present
|
|
400
|
+
* with `undefined` absent), every object in them copied. **On an instance of a DOCUMENT type only** — one of a CLASS
|
|
401
|
+
* type is refused (`UndeclaredKey`): the class receives the instance key and owns how its pool is built.
|
|
402
|
+
*/
|
|
403
|
+
pool?: NodeTypeDeclaration['pool'];
|
|
366
404
|
}
|
|
367
405
|
/** A resource group the runtime constructs — an instance of a group TYPE, by name, with the config its factory's schema admits. */
|
|
368
406
|
export interface GroupInstance {
|
|
@@ -434,6 +472,8 @@ export interface ResolvedPool {
|
|
|
434
472
|
config: unknown;
|
|
435
473
|
/** What the derivation returned, held to `PoolSpec`'s shape and the worker's `configSchema`. */
|
|
436
474
|
spec: PoolSpec;
|
|
475
|
+
/** A named instance's OWN pool options, COPIED, a key present with `undefined` dropped (it overrides nothing) — v0.37, ADR 0099; absent where it declares none, and on every default instance. */
|
|
476
|
+
pool?: NodeTypeDeclaration['pool'];
|
|
437
477
|
}
|
|
438
478
|
/** One resource group, resolved: its factory and its checked config. `create` has NOT been called. */
|
|
439
479
|
export interface ResolvedGroup {
|
|
@@ -552,7 +592,7 @@ export interface MapNode {
|
|
|
552
592
|
* against whatever that resolves to.
|
|
553
593
|
*/
|
|
554
594
|
over: string;
|
|
555
|
-
/** **One** branch entry id, whose kind is a `task` (`FD-V25`). Not a list. */
|
|
595
|
+
/** **One** branch entry id, whose kind is a `task` or — since v0.42 — an `ask` (`FD-V25`). Not a list. */
|
|
556
596
|
branch: string;
|
|
557
597
|
/**
|
|
558
598
|
* **What this node receives, and therefore what `over` is a key on** —
|
|
@@ -601,7 +641,7 @@ export interface EndNode {
|
|
|
601
641
|
export interface GateNode {
|
|
602
642
|
id: string;
|
|
603
643
|
kind: 'gate';
|
|
604
|
-
/** A registered GATE type's name — a built-in (`distinct`) or `Registry.gateTypes`' (`FD-V39`). */
|
|
644
|
+
/** A registered GATE type's name — a built-in (`distinct`, `if`, `switch`) or `Registry.gateTypes`' (`FD-V39`). */
|
|
605
645
|
type: string;
|
|
606
646
|
/**
|
|
607
647
|
* **What the gate's type is configured with** — a plain object its type's `settingsSchema` accepts
|
|
@@ -641,14 +681,54 @@ export interface GateContext {
|
|
|
641
681
|
* (P24 decision 2, ADR 0066). Code, not a document entry: `fn` is a function, which a JSON registry
|
|
642
682
|
* cannot carry (ADR 0002 rule 1), so a consumer's types are registered in `Registry.gateTypes` the way
|
|
643
683
|
* a language adapter's `compile` is supplied in code.
|
|
684
|
+
*
|
|
685
|
+
* **Its routes are declared STATICALLY or DERIVED from the gate's own settings — exactly one of the two**
|
|
686
|
+
* ([ADR 0092](../../doc/decisions/0092-a-gate-types-routes-are-declared-statically-or-derived-from-its-node.md),
|
|
687
|
+
* v0.30): a `StaticGateType` carries `routes`, `defaultRoute` and `keyResolvedRoutes?`, the same for every
|
|
688
|
+
* gate naming it; a `DerivedGateType` carries `routesFor(settings)` IN PLACE of the three, so two gates of
|
|
689
|
+
* one type may have two route sets. Every reader of a gate's routes reads the gate's RESOLVED set
|
|
690
|
+
* (`routesOf`), never the type's members. A value carrying both, or neither, is refused (`FD-V39`,
|
|
691
|
+
* `GateTypeRefused`).
|
|
644
692
|
*/
|
|
645
|
-
export
|
|
693
|
+
export type GateType = StaticGateType | DerivedGateType;
|
|
694
|
+
/** **A gate type whose routes are its NODE's** — `routesFor` in place of `routes`, `defaultRoute` and `keyResolvedRoutes` (ADR 0092). */
|
|
695
|
+
export interface DerivedGateType {
|
|
696
|
+
/**
|
|
697
|
+
* **The routes of ONE gate, from that gate's settings** — `{ routes, defaultRoute, keyResolvedRoutes? }`,
|
|
698
|
+
* held to the clauses a static type's three members are. Called once per gate at instantiation, after
|
|
699
|
+
* `FD-V40` passed, with a COPY of the settings (`{}` when the gate declares none); every reader — `FD-V41`'s
|
|
700
|
+
* count, the default edge, `FD-R5`, the wiring check's guarantee — reads what it returned. **A pure function
|
|
701
|
+
* of the settings**, as `fn` is of its context (Q9): the validator and each driver ask it separately, and a
|
|
702
|
+
* resume asks it again. A throw or a malformed set is refused at the GATE, `FD-V39`.
|
|
703
|
+
*/
|
|
704
|
+
routesFor(settings: Readonly<Record<string, unknown>>): Pick<StaticGateType, 'routes' | 'defaultRoute' | 'keyResolvedRoutes'>;
|
|
705
|
+
readonly routes?: never;
|
|
706
|
+
readonly defaultRoute?: never;
|
|
707
|
+
readonly keyResolvedRoutes?: never;
|
|
708
|
+
/** What a gate's `settings` must satisfy, in the built-in subset (ADR 0053). Absent means UNCHECKED (P18 decision 3). */
|
|
709
|
+
readonly settingsSchema?: JsonSchema;
|
|
710
|
+
/**
|
|
711
|
+
* **What the settings must satisfy beyond the schema** — a message naming what is wrong, or `null`. Run by
|
|
712
|
+
* `FD-V40` once the settings are a plain object the `settingsSchema` accepts, with a COPY of them; a message
|
|
713
|
+
* is reported under `FD-V40`, and a throw or a return that is neither a string nor `null` under `FD-V39`
|
|
714
|
+
* (ADR 0092). The subset cannot state a grammar (ADR 0053), so a type that needs one states it here.
|
|
715
|
+
*/
|
|
716
|
+
settingsProblem?(settings: Readonly<Record<string, unknown>>): string | null;
|
|
717
|
+
/** The decision: one of THIS GATE's routes, synchronously — a route outside the set `routesFor` returned for the gate HALTS the run (`FD-R5`). */
|
|
718
|
+
fn(ctx: GateContext): string;
|
|
719
|
+
}
|
|
720
|
+
/** **A gate type whose routes are the same for every gate naming it** — the interface as ADR 0066 wrote it; `distinct` is one. */
|
|
721
|
+
export interface StaticGateType {
|
|
646
722
|
/** Every route `fn` may return, each in `FD-V16`'s charset, distinct, at least one. Every one must be wired by exactly one edge (`FD-V41`). */
|
|
647
723
|
readonly routes: readonly string[];
|
|
648
724
|
/** What an edge with no `route` carries. One of `routes` — and NOT necessarily the first. */
|
|
649
725
|
readonly defaultRoute: string;
|
|
726
|
+
/** Absent on a static type: its routes are declared, not derived (ADR 0092). */
|
|
727
|
+
readonly routesFor?: never;
|
|
650
728
|
/** What a gate's `settings` must satisfy, in the built-in subset (ADR 0053). Absent means UNCHECKED (P18 decision 3). */
|
|
651
729
|
readonly settingsSchema?: JsonSchema;
|
|
730
|
+
/** As `DerivedGateType.settingsProblem`: run by `FD-V40` after the schema, its message reported under it. */
|
|
731
|
+
settingsProblem?(settings: Readonly<Record<string, unknown>>): string | null;
|
|
652
732
|
/**
|
|
653
733
|
* **The routes on which the gate's KEY PATH resolved** — a subset of `routes` (`FD-V39`'s second clause, as every
|
|
654
734
|
* other malformed member of this interface is), OPTIONAL, and
|
|
@@ -666,12 +746,60 @@ export interface GateType {
|
|
|
666
746
|
* and a type must not read this member as a promise about the leaf's TYPE.
|
|
667
747
|
*/
|
|
668
748
|
readonly keyResolvedRoutes?: readonly string[];
|
|
669
|
-
/** The decision: one of `routes`, synchronously. A route not declared
|
|
749
|
+
/** The decision: one of `routes`, synchronously. A route not declared HALTS the run by name (P24 decision 8 — `FD-R5`, `UndeclaredRoute`); a throw halts it with the thrown error, as a predicate's does. */
|
|
670
750
|
fn(ctx: GateContext): string;
|
|
671
751
|
}
|
|
672
752
|
/** A consumer's gate types, keyed by the name a gate's `type` gives. A `Map` or a plain object, as `nodeTypes` is. */
|
|
673
753
|
export type GateTypes = ReadonlyMap<string, GateType> | Readonly<Record<string, GateType>>;
|
|
674
|
-
|
|
754
|
+
/**
|
|
755
|
+
* **An ASK: a node that waits for a PERSON, by design** — `spec/flow-definition.md` section 2 (v0.42),
|
|
756
|
+
* [P35](../../doc/plans/p35-may-a-node-wait-for-a-person-by-design.md) stop-and-asks (a) and (h),
|
|
757
|
+
* [ADR 0108](../../doc/decisions/0108-an-ask-is-a-seventh-node-kind-with-a-task-id-and-no-dispatch.md).
|
|
758
|
+
*
|
|
759
|
+
* It runs NO worker and is NEVER dispatched, yet it has a TASK ID (`spec/task-id.md` v0.13) — the address a
|
|
760
|
+
* person's answer is given to, `resolve(taskId, …)`, one per map item where it sits in a `map` region. The answer
|
|
761
|
+
* is its OUTPUT: a later node may reference it by `needs` (`FD-V27`), and its edges ROUTE like a task's — `on:
|
|
762
|
+
* ['done' | 'failed']`, a `failed` answer being the person DECLINING, and a `when` over `outcome.result`, the
|
|
763
|
+
* answer. Allowed wherever a `task` is, the entry included. **What a task's WORKER reads it does not carry** —
|
|
764
|
+
* `type`, `pool`, `optional`, `retryPolicy`, `workerGroups` and `transform` are each refused by `FD-V47`, because
|
|
765
|
+
* nothing would read them: there is no worker, no scheduler task and no wrapper to evaluate a transform in
|
|
766
|
+
* (`FD-C6`, P35 decision 6).
|
|
767
|
+
*
|
|
768
|
+
* **BREAKING** (0.8.0, P35 decision 8): `FlowNode` gains a seventh member, so a consumer's `switch` over
|
|
769
|
+
* `node.kind` with a `never` check stops compiling until it names `'ask'`.
|
|
770
|
+
*
|
|
771
|
+
* **Valid since v0.42 and run since W180** — until then every `Driver` refuses the run by name where a branch
|
|
772
|
+
* ENTERS one (`enter()`), as W92's gate was refused until W93.
|
|
773
|
+
*/
|
|
774
|
+
export interface AskNode {
|
|
775
|
+
id: string;
|
|
776
|
+
kind: 'ask';
|
|
777
|
+
/**
|
|
778
|
+
* **What a UI shows the person — opaque.** A plain JSON object the library NEVER reads (`FD-V21` refuses one that
|
|
779
|
+
* is not a plain object): the question, a form hint. Read from the definition, as a gate's settings are read by
|
|
780
|
+
* its type.
|
|
781
|
+
*/
|
|
782
|
+
settings?: Readonly<Record<string, unknown>>;
|
|
783
|
+
/**
|
|
784
|
+
* **What a `done` answer must satisfy** — a JSON Schema in the built-in subset, held to it at load exactly as a
|
|
785
|
+
* worker's schemas are (`FD-V48`, ADR 0053), its `examples` held to it too (ADR 0056). Absent, an answer is held
|
|
786
|
+
* to nothing. A `failed` answer — a decline — is held to nothing either way. What it holds at run time is W180's
|
|
787
|
+
* (`FD-R4`'s resolve boundary).
|
|
788
|
+
*/
|
|
789
|
+
answerSchema?: JsonSchema;
|
|
790
|
+
/**
|
|
791
|
+
* **What reaches the ask** — `FD-C1`, `FD-V26`-`FD-V29`, composed in the driver as a task's is. Optional: without
|
|
792
|
+
* one, the ordinary edge's value. What reached it is what the person is shown, and what W180 keeps.
|
|
793
|
+
*/
|
|
794
|
+
needs?: Needs;
|
|
795
|
+
/** Routed like a task's: `on` and `when`, a default edge for every terminal state an edge opts into (`FD-V7`). */
|
|
796
|
+
edges: Edge[];
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* **Seven kinds since v0.42** (`ask`, W179). **BREAKING for an exhaustive consumer `switch`** each time a member
|
|
800
|
+
* is added — `gate` at 0.6.0, `ask` at 0.8.0.
|
|
801
|
+
*/
|
|
802
|
+
export type FlowNode = TaskNode | FanoutNode | MapNode | JoinNode | EndNode | GateNode | AskNode;
|
|
675
803
|
export interface FlowDefinition {
|
|
676
804
|
flowId: string;
|
|
677
805
|
version: number;
|
|
@@ -726,7 +854,8 @@ export interface Registry {
|
|
|
726
854
|
* **A consumer's GATE types, beside the built-ins** — the sixth set, v0.23 (W92, ADR 0066). **Absent
|
|
727
855
|
* means the BUILT-INS ALONE** — `distinct` is always there, so this set only ever ADDS; a name that
|
|
728
856
|
* is a built-in's is refused (`NameCollision` at construction, `FD-V39` reached here directly). The
|
|
729
|
-
* validator reads
|
|
857
|
+
* validator reads each gate's route set (`routesOf` — the static members, or `routesFor` over the gate's
|
|
858
|
+
* settings, v0.30), `settingsSchema` and `settingsProblem`; the driver reads `fn` too. **A driver
|
|
730
859
|
* is handed the set as `DriverOptions.gateTypes`** since W93 — the runtime's road is
|
|
731
860
|
* `runtime.registry.gateTypes`, from `RegistryCode.gateTypes`. *(Until W93 no driver carried it and
|
|
732
861
|
* every gate flow was refused at construction.)*
|
|
@@ -740,7 +869,7 @@ export interface Registry {
|
|
|
740
869
|
* legitimately violate more than one rule.
|
|
741
870
|
*/
|
|
742
871
|
export interface Finding {
|
|
743
|
-
/** `FD-V1` … `FD-V46
|
|
872
|
+
/** `FD-V1` … `FD-V46` from the validator; `runtime.check` adds `FD-R6` (ADR 0097). Never renumbered, so it is safe to assert on. */
|
|
744
873
|
rule: string;
|
|
745
874
|
/** Node id, edge index, or document-level `null`. */
|
|
746
875
|
at: string | null;
|