runtime: bind task admission to a capability-homogeneous worker fleet
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Observed behavior
#1255 pins a workflow's complete task-name requirement set and checks it before effects against the worker that receives the admission activity. That closes known-unavailable programs and keeps local rehearsals honest, but it cannot prove a heterogeneous Temporal fleet: a capable worker may pass admission, an early task may produce an effect, and a later task may be dispatched to another poller whose registry lacks that task.
Temporal Worker Deployment Versioning normally routes a pinned workflow and same-queue activities to one deployment version, but the version identifies deployment/build configuration, not the runtime plugin directory or an embedder's installed registry. An unversioned fleet, workers misconfigured under one build ID, or an independently routed activity queue can therefore still hold different task sets. Dispatch-time UnknownTask remains fail-closed, but it is too late to preserve the no-effect guarantee.
Evidence
PR #1267's CheckTaskCapabilities activity compares the pinned names with TaskRuntimeConfig.taskNames frozen by the single worker that executes that activity. Subsequent task activities independently read the registry of whichever worker executes them. pkg/flowstate/v1/engine/dispatch_unknown_task_test.go and plugins.go already document that workflow and activity workers sharing a queue may differ during rollout.
The review trace is https://github.com/picatz/flowstate/pull/1267#discussion_r3890685452. #1255 explicitly retains dispatch-time lookup as the backstop for fleet drift; this issue owns the stronger fleet-wide guarantee rather than expanding that bounded schema/runtime slice into a generic backend or deployment-control abstraction.
Desired outcome
A durable run is admitted only when every worker eligible to execute its task activities proves one capability-homogeneous task set, or when the control plane can prove the required names are in the eligible fleet's intersection. The proof is tied to Temporal routing/version identity and remains deterministic across replay and Continue-As-New.
Acceptance criteria
- A deterministic integration test uses heterogeneous workers eligible on one logical queue: one can execute an observable first effect and another lacks a later required task. The run is refused before the first effect.
- Admission and every task activity for the admitted segment are routed only to workers covered by the same capability proof, or admission checks a control-plane-owned intersection covering all eligible workers.
- Worker join/leave, rollout, stale heartbeat, and unavailable-control-plane semantics are defined fail-closed without putting live registry reads in workflow code.
- Continue-As-New defines whether and how the fleet capability proof is renewed while preserving replay of prior segments.
- Worker Deployment Versioning membership, unversioned opt-out behavior, and independently routed activity queues are covered explicitly.
- The existing Protobuf task requirement snapshot and
Registryremain the sources of requirement and executable truth; no second capability registry, generic backend interface, or third runtime is introduced. - Secrets remain references and no resolved values enter capability advertisements or durable history.
- Dispatch-time
UnknownTaskremains the backstop for unknown external outcomes after a valid proof.
Open decision
Choose the smallest existing Temporal/control-plane ownership point for the proof: capability-homogeneous deployment-version routing versus a bounded fleet-intersection record. The decision must account for plugin directories and embedder-installed registries that can differ even when binaries share a build ID.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with pkg/flowstate/v1/engine/dispatch_unknown_task_test.go and plugins.go, then trace CheckTaskCapabilities, TaskRuntimeConfig.taskNames, and Registry. Read the linked PR discussion and existing task requirement snapshot behavior before choosing the Temporal/control-plane ownership point. Done means the acceptance criteria are covered by deterministic integration tests, including routing, fleet changes, Continue-As-New, and fail-closed cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend-api-design, distributed-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100