On the substrate page in the UI, the associated actors in the workers lists aren't updating when I send a message, even though the actor shows that it is scheduled on a worker pod on the actors list. It sounds like this is an issue with the worker -> actor mapping in the API response.
🤖 written by Claude (start)
🎯 Affected Service(s)
Controller Service
🚦 Impact/Severity
Minor inconvenience
🐛 Bug Description
GetSubstrateStatus never sets SubstrateWorker.actor_id, actor_template or actor_namespace, so every worker reports holding nothing and the page reads that as an idle pod. The actors half of the same response is correct; only the worker → actor direction is missing.
🔄 Steps To Reproduce
- On a cluster with ate-api configured, send a message so an actor is scheduled.
- Open the Substrate page. Actors names the worker pod; Workers shows
idle for that same pod.
🔍 Additional Context
Introduced in #2697 (a9c209f6), the substrate v0.0.25 update. That release removed the singular assignment from WorkerStatus, so the PR correctly deleted the lines reading it — but nothing replaced them:
- assignment := worker.GetStatus().GetAssignment()
- ActorNamespace: assignment.GetActorTemplateRef().GetAtespace(),
- ActorTemplate: assignment.GetActorTemplateRef().GetName(),
- ActorID: assignment.GetActor().GetName(),
Under v0.0.25 the binding lives only on the actor, as ActorStatus.worker_assignment, so the worker side has to be joined from the actor list — in the service, where both whole lists are in hand rather than in the UI, which only ever holds pages.
Worth settling: a v0.0.25 worker holds several actors and SubstrateWorker has room for one, so either the pick is made deterministic or system.proto gains a repeated field.
🧭 Fixing it
The binding lives only on the actor under v0.0.25 (ActorStatus.worker_assignment), so the worker side has to be joined from the actor list. That belongs in system.Service.GetSubstrateStatus, which holds both complete lists — done in the UI it would match only where two paged reads overlap, and the reads that reach a browser are pages.
Two decisions come with it, which is why this is not a UI change:
- A worker holds several actors, and
SubstrateWorker has room for one. Adding actor_status beside actor_id/actor_template/actor_namespace deepens a model the API already contradicts: a pod running three actors cannot be represented, and actor_id: "" with actor_status: "Running" can be. A repeated placement message replacing the four singular fields matches the backend, and is cheap now — GetSubstrateStatus has exactly two consumers, this controller and the UI, with no Python or CLI client.
ActorStatusLabel falls back to the wire constant for a state it has not been taught, and callers sort on what it sends while displaying what they sorted — so ACTOR_STATE_DELETING files itself under A and reads as "Deleting" beneath a heading that says sorted by status. Naming every value fixes the sort and the display together.
🚧 Blocked on this
The Substrate page shows the actor mix as a bar per card. The Workers card has no bar, because workerFromProto sets no actor fields at all — actor_id is empty on every cluster, so a bar there would read as an idle fleet while pods are running. Once this lands the workers bar can be drawn, coloured by what each pod is holding.
🤖 written by Claude (end)
On the substrate page in the UI, the associated actors in the workers lists aren't updating when I send a message, even though the actor shows that it is scheduled on a worker pod on the actors list. It sounds like this is an issue with the worker -> actor mapping in the API response.
🤖 written by Claude (start)
🎯 Affected Service(s)
Controller Service
🚦 Impact/Severity
Minor inconvenience
🐛 Bug Description
GetSubstrateStatusnever setsSubstrateWorker.actor_id,actor_templateoractor_namespace, so every worker reports holding nothing and the page reads that as an idle pod. The actors half of the same response is correct; only the worker → actor direction is missing.🔄 Steps To Reproduce
idlefor that same pod.🔍 Additional Context
Introduced in #2697 (
a9c209f6), the substrate v0.0.25 update. That release removed the singular assignment fromWorkerStatus, so the PR correctly deleted the lines reading it — but nothing replaced them:Under v0.0.25 the binding lives only on the actor, as
ActorStatus.worker_assignment, so the worker side has to be joined from the actor list — in the service, where both whole lists are in hand rather than in the UI, which only ever holds pages.Worth settling: a v0.0.25 worker holds several actors and
SubstrateWorkerhas room for one, so either the pick is made deterministic orsystem.protogains a repeated field.🧭 Fixing it
The binding lives only on the actor under v0.0.25 (
ActorStatus.worker_assignment), so the worker side has to be joined from the actor list. That belongs insystem.Service.GetSubstrateStatus, which holds both complete lists — done in the UI it would match only where two paged reads overlap, and the reads that reach a browser are pages.Two decisions come with it, which is why this is not a UI change:
SubstrateWorkerhas room for one. Addingactor_statusbesideactor_id/actor_template/actor_namespacedeepens a model the API already contradicts: a pod running three actors cannot be represented, andactor_id: ""withactor_status: "Running"can be. Arepeatedplacement message replacing the four singular fields matches the backend, and is cheap now —GetSubstrateStatushas exactly two consumers, this controller and the UI, with no Python or CLI client.ActorStatusLabelfalls back to the wire constant for a state it has not been taught, and callers sort on what it sends while displaying what they sorted — soACTOR_STATE_DELETINGfiles itself under A and reads as "Deleting" beneath a heading that says sorted by status. Naming every value fixes the sort and the display together.🚧 Blocked on this
The Substrate page shows the actor mix as a bar per card. The Workers card has no bar, because
workerFromProtosets no actor fields at all —actor_idis empty on every cluster, so a bar there would read as an idle fleet while pods are running. Once this lands the workers bar can be drawn, coloured by what each pod is holding.🤖 written by Claude (end)