@@ -27,16 +27,15 @@ Proposed. Revised after the review on #72047.
2727
28281 . ** ` dag.task(handler) ` returns a factory, and the task id is optional.** With no id the task takes
2929 the handler's function name (` dag.task(extract) ` → task ` "extract" ` ); ` dag.task(taskId, handler) `
30- sets it explicitly, which an anonymous handler must do. Calling the factory both places the task in
31- the Dag and supplies its arguments, in the order the handler declares them
32- (` load(transform(extract(), "us")) ` ). A handler that declares a single object of named arguments can
33- also be called with that object — the shape Python TaskFlow uses for
34- ` load(transformed=transform(...)) ` .
35- 2 . ** The call graph is the task graph.** ` tsc ` checks every wired key against the handler's own
36- parameter type, and a ` TaskRef ` exists only once its producing call has returned, so a cycle
37- through arguments is unrepresentable rather than rejected by a validator. A reference passed by
38- position is checked against the argument's own type, which is what tells the two call shapes apart
39- when a handler declares a single argument.
30+ sets it explicitly, which an anonymous handler must do. A handler takes one object of named
31+ arguments, and calling the factory both places the task in the Dag and names each of its inputs
32+ (` load({ total: transform({ rows: extract(), region: "us" }) }) ` ) — the shape Python TaskFlow uses
33+ for ` load(transformed=transform(...)) ` . ` withArgList(...) ` supplies the same inputs in the order
34+ the handler destructures them, for a call that reads better that way.
35+ 2 . ** The call graph is the task graph.** ` tsc ` checks every named input against the handler's own
36+ argument type, and a ` TaskRef ` exists only once its producing call has returned, so a cycle
37+ through arguments is unrepresentable rather than rejected by a validator. A listed call is checked
38+ by value type, and which argument each value supplies is the position it was given in.
40393 . ** Every task is called exactly once.** An uncalled task fails when the Dag is read, so none can be
4140 silently left out of the graph.
42414 . ** ` before ` and ` after ` draw order-only edges** — the TypeScript pair for ` >> ` and ` << ` , both
@@ -149,20 +148,20 @@ convention.
149148 by design. Native declaration is what fills them, generated from the serialized-Dag JSON schema the
150149 way ` src/generated/supervisor.ts ` is. This ADR does not choose those fields; it fixes where an
151150 author writes them.
152- - ` TaskOptions ` carries the spec and the handler's positional argument names, which the packer fills in
153- from the parameter list so the Dag names each argument as its handler does. With wiring moved to the
154- factory call, ` inputs ` is no longer an option.
151+ - ` TaskOptions ` carries the task's spec and nothing else: the names on the wire are the keys of the
152+ call itself. With wiring moved to the factory call, ` inputs ` is no longer an option.
155153- ` TaskHandlerArgs ` is removed from the public API, ` DagRegistry ` becomes ` Bundle ` , and
156154 ` serveDags(registry) ` becomes ` bundle.serve() ` , which breaks
157155 0.1.0-beta1 authors; see [ ADR-0001] ( 0001-mixed-lang-dag-interface.md ) for the shipped call sites
158156 that change.
159157
160158## Alternatives
161159
162- - ** Named-only wiring** , rejected in the review on #73435 : naming every input reads well at twenty
163- tasks but forces an object around a single argument, and positional calls are what TypeScript
164- authors write. Both are offered, and the handler's own parameter list decides which one a task can
165- use.
160+ - ** Positional handlers** , ` async (rows: number, region: string) => ... ` , offered first and then
161+ dropped: a positional parameter list has no names on the wire unless the SDK reads them out of the
162+ handler's source, and a single object of named arguments is what a TypeScript library takes
163+ anyway. The handler is object-only, and ` withArgList(...) ` keeps the positional call site for the
164+ cases that read better in order.
166165- ** Injected ` ctx ` /` client ` arguments** , mimicking the Python signature. Rejected, per the above and
167166 because feeling native to TypeScript matters more than matching Python's parameter list.
168167
@@ -181,17 +180,19 @@ convention.
181180- ** The spec argument already has its slot.** ` dag.task(taskId, handler, options) ` reads ` { spec = {} } `
182181 and runs ` validateEmptySpec ` on it (` ts-sdk/src/sdk/dag.ts ` ), so task fields land on a path that
183182 exists rather than a new one.
184- - ** A positional argument binds by order, and its name is a label.** The serialized Dag names each
185- argument, so the packer reads the names from the handler's parameter list; ` arg0 ` , ` arg1 ` and so on
186- stand in for a name it cannot see, without changing which value reaches which argument.
183+ - ** A listed call binds by order, and the names still come from the handler.** The serialized Dag
184+ names every argument, so ` withArgList(...) ` is zipped with the keys the handler destructures, read
185+ off its argument pattern at the call. A pattern that cannot be read that way, such as one with a
186+ default or a rest element, is refused rather than guessed at, and its task is called by name.
187187- ** A ` TaskRef ` is inert** — a handle for wiring, not a promise. Nothing in a Dag file executes a task
188188 body.
189- - ** A defaulted task id is resolved at pack time, not read at runtime.** esbuild renames function
190- identifiers, so ` handler.name ` in a packed bundle is the minified name, not the author's. The pack
191- step (` ts-sdk/src/cli/pack.ts ` ) therefore reads an omitted id from the handler's declared name in
192- source and writes it into the registration, rather than depending on ` handler.name ` or enabling
193- esbuild's ` keepNames ` across the whole bundle. A handler with no source name leaves nothing to
194- read, which is why an anonymous handler must state its id.
189+ - ** A defaulted task id is read off the handler itself.** The pack step (` ts-sdk/src/cli/pack.ts ` )
190+ minifies and passes esbuild's ` keepNames ` , so ` handler.name ` is the author's in a packed bundle as
191+ much as in one run from source; an argument name is a property name, which minification leaves
192+ alone. Rewriting the call at pack time was tried first and dropped: it needed a TypeScript parser
193+ in the packer to tell a real ` .task( ` from one inside a string or a comment, and it could not see a
194+ handler declared in another module. A handler with no name leaves nothing to read, which is why an
195+ anonymous handler must state its id.
195196- ** ` withArgNames ` and the name folding behind it** ([ ADR-0001] ( 0001-mixed-lang-dag-interface.md ) )
196197 exist for the mixed-language case and are never needed here: both ends of every name are
197198 TypeScript, so ` tsc ` checks the wiring end to end and there is no foreign name to reconcile.
0 commit comments