Umbrella Rust Worker Parity Gaps - noetl/ai-meta GitHub Wiki
ai-task: #47 โ closed, #48 โ closed ยท Surfaced: 2026-06-02 (kind regression run) ยท Filed: 2026-06-02 ยท Closed: 2026-06-02 ยท Parent umbrella: Rust Worker Migration ยท Status: Both gaps shipped โ Gap 1 via noetl/noetl#662 (v4.12.0), Gap 2 via noetl/worker#40 (v5.10.0). Kind regression baseline now ~52/53.
Close the two parity gaps surfaced by the 2026-06-02 kind regression run so the Rust worker handles the production playbook mix without falling back to the Python pool for these specific cases.
#47 ยท Resolved via noetl/noetl#662 (v4.12.0) + noetl/ops#145
The Rust worker doesn't implement the task_sequence tool kind.
~25 sub-playbooks in the regression suite use it
(tests/control-flow/, test/vars_simple, vars_test/, etc.) and all
failed on the Rust pool.
Original fingerprint:
ERROR noetl_worker::worker: Command execution failed
execution_id=640421571655369719
command_id=640421579230281755
step=process:task_sequence
error=Tool not found: task_sequence
Decision: Option B โ route to python pool.
Reading the Python source disambiguated the question. task_sequence
is an engine-level pipeline construct, not a tool kind in the
noetl-tools sense:
-
noetl/worker/task_sequence_executor.py(~1.2k LoC) shipsTaskSequenceExecutorwith pipeline-local data threading via_prev(Clojure-style->), per-task flow-control rules (continue/retry/break/jump/failmatched onwhenpredicates over the task's outcome envelope), template bindings for_task/_prev/_attempt/output/results/ctx.*/iter.*, retry/backoff machinery, and a parametrized policy DSL. - ~11 special-case sites in
noetl/core/dsl/engine/executor/{events,commands,state,store,common}.pykey off the synthetic<parent>:task_sequencestep name โ covers loop-state init, step.exit handling, replay state restoration, command emission, parent-step normalization, and event correlation. - Rust workspace (
repos/worker,repos/tools,repos/cli) had zero references totask_sequence.
Porting that surface to Rust is multi-week work with no runtime
benefit โ each inner task's tool already dispatches through the
worker's existing _execute_tool callback. Routing the kind to
the python pool is the right shape.
Implementation: one-line addition to POOL_FILTER_MAP in
noetl/core/runtime/pool_routing.py:
POOL_FILTER_MAP = {
"agent": "python",
"task_sequence": "python", # NEW
}When the routing flag is on, the command publishes to
noetl.commands.python.<eid>; the Rust pool's consumer's filter
(noetl.commands.shared.>) no longer matches; the Python pool's
catch-all consumer (noetl_worker_pool, filter=None) picks it up
and TaskSequenceExecutor runs the pipeline.
Kind validation (2026-06-02): Python pool delivery delta +1 โ
;
Rust pool delivery delta 0 โ
; no Tool not found line in Rust
worker logs โ
.
#48 ยท Resolved via noetl/worker#40 (v5.10.0) + noetl/ops#146
The Rust worker passed credential alias strings (e.g.
"pg_local") through to the postgres tool as raw strings.
Python resolves the alias against the keychain at dispatch time
and substitutes the AuthConfig struct. ~10 sub-playbooks affected
(every postgres step that uses auth: "<alias>" instead of inline
credentials).
Original fingerprint:
ERROR noetl_worker::worker: Command execution failed
execution_id=640418972487123831
command_id=640418976614318976
step=create_test_results_table
error=invalid type: string "pg_local", expected struct AuthConfig
Implementation:
New module src/executor/auth_alias.rs (~430 LoC, 11 unit tests + 3
HTTP-integration tests) runs before serde_json::from_value in
the command dispatch path:
- Detect string value in the
auth:slot of the tool config JSON. - Fetch the credential via the new
ControlPlaneClient::get_credential(alias, execution_id)method (GET /api/credentials/{alias}?include_data=true). - Branch on the credential's
typefield:-
postgresโ stripauth; mergedb_host/db_port/db_user/db_password/db_nameinto the postgres tool's flat connection fields (host/port/user/password/database). Mirrors Python'snormalize_postgres_fields. Unprefixed keys (host,port, ...) also accepted. -
bearer/bearer_tokenโ replaceauthwith the noetl-tools shape{type: bearer, credential: <alias>}+ seed the token intoctx.secretsso the existingAuthResolver.resolve_bearerkeychain lookup fires. -
api_keyโ{type: api_key, credential: <alias>, header: <data.header or "X-API-Key">}+ secret seed. -
basicโ{type: basic, credential: <alias>, username: <data.username>}+ secret seed of the password. - Anything else โ clear error naming the offending type.
- Missing alias (server 404) โ clear
Credential alias '<name>' not found in keychainerror.
-
Idempotent: if auth is already a struct (or absent), the helper is
a no-op + no HTTP call.
Playbook-level overrides win over keychain defaults โ port: 6543
set on the step keeps that value.
Kind validation (2026-06-02):
==> Probing noetl.event for command lifecycle
command.issued probe status=PENDING worker=
command.claimed probe status=RUNNING worker=noetl-worker-rust-d85576785-tr7zg
call.done probe status=COMPLETED worker=
command.completed probe status=COMPLETED worker=
โ
execution reached command.completed
โ
Rust worker claimed the command (worker_id=noetl-worker-rust-...)
โ
Rust worker did not log 'expected struct AuthConfig'
| Gap | PR(s) | Status | Wiki updates |
|---|---|---|---|
| #47 task_sequence | noetl/noetl#662 (v4.12.0) + noetl/ops#145 | โ shipped | noetl wiki pool_routing task_sequence row added |
| #48 alias resolution | noetl/worker#40 (v5.10.0) + noetl/ops#146 | โ shipped | noetl/worker wiki worker-credentials gained a "Two ways playbooks reference a credential" section covering the alias-string shape + the 4 supported credential types (postgres, bearer, api_key, basic) |
| Date | Event |
|---|---|
| 2026-06-02 | Both gaps surfaced + filed during kind regression run against worker v5.9.0 (master_regression_test execution_id 640418956389385052). Session details. |
| 2026-06-02 | Run statistics: 53 sub-playbooks attempted, 17 COMPLETED / 53 FAILED / 15 zombie RUNNING. 468 commands processed through noetl_worker_pool_shared consumer. |
| 2026-06-02 | Gap #1 (task_sequence) shipped via noetl/noetl#662 (v4.12.0) + noetl/ops#145. POOL_FILTER_MAP gains "task_sequence": "python"; routes to the catch-all Python consumer. Kind-validated end-to-end. |
| 2026-06-02 | Gap #2 (alias resolution) shipped via noetl/worker#40 (v5.10.0) + noetl/ops#146. New src/executor/auth_alias.rs resolves string auth: values before serde deserialization; 4 credential types supported (postgres / bearer / api_key / basic); 14 new tests. Kind-validated end-to-end. |
| 2026-06-02 | Umbrella closed. Regression baseline now ~52/53; remaining ~1 failure is external deps (Duffel test API key rotation), out of scope for Rust parity. |
This umbrella is closed. Follow-up work, if any, lives under the parent Rust Worker Migration umbrella.
- Umbrella: Rust Worker Migration โ parent.
- Sessions Log: 2026-06-02 โ the regression run that surfaced both gaps.
- noetl-tools wiki: https://github.com/noetl/tools/wiki
- noetl-worker wiki: https://github.com/noetl/worker/wiki