From 603f82c1ae699463dc7730c20ef1e8e22c2ec8de Mon Sep 17 00:00:00 2001 From: Ross Nelson Date: Tue, 8 Sep 2026 16:28:42 -0400 Subject: [PATCH 1/4] Propose ComputeProviderStatus in GetSystemInfo RFC, not for merge as-is. Proposes reporting compute providers as a repeated message on GetSystemInfoResponse instead of adding one boolean to Capabilities per provider. - enums/v1/compute.proto: ComputeProviderReleaseStage - compute/v1/status.proto: ComputeProviderStatus (type, enabled, release_stage) - GetSystemInfoResponse.compute_providers = 3 - Marks server_scaled_provider_cloud_run as superseded, kept for wire compatibility, and closes the door on further per-provider booleans The boolean pattern answers only "is this one provider usable". Every new provider costs a proto field, an api release, and a server release before a client can gate on it, and it carries no release stage, so each client hardcodes its own table. Both problems are live: Cloud Run's capability landed a month after the UI shipped the option, the server still does not set it, and AgentCore is merged in temporal-auto-scaled-workers and the CLI with no capability field at all. OpenAPI specs are not regenerated here; buf could not be installed in this environment. Regenerate before this leaves draft. --- temporal/api/compute/v1/status.proto | 37 +++++++++++++++++++ temporal/api/enums/v1/compute.proto | 30 +++++++++++++++ .../workflowservice/v1/request_response.proto | 20 ++++++++++ 3 files changed, 87 insertions(+) create mode 100644 temporal/api/compute/v1/status.proto create mode 100644 temporal/api/enums/v1/compute.proto diff --git a/temporal/api/compute/v1/status.proto b/temporal/api/compute/v1/status.proto new file mode 100644 index 000000000..264b8faef --- /dev/null +++ b/temporal/api/compute/v1/status.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; + +package temporal.api.compute.v1; + +option go_package = "go.temporal.io/api/compute/v1;compute"; +option java_package = "io.temporal.api.compute.v1"; +option java_multiple_files = true; +option java_outer_classname = "StatusProto"; +option ruby_package = "Temporalio::Api::Compute::V1"; +option csharp_namespace = "Temporalio.Api.Compute.V1"; + +import "temporal/api/enums/v1/compute.proto"; + +// ComputeProviderStatus describes one compute provider this Service knows +// about, so a client can discover which providers exist and how to present +// them without hardcoding a list of its own. +// +// A Service reports a provider it recognizes even when that provider is +// disabled, so a client can tell "this Service has never heard of AgentCore" +// apart from "this Service knows AgentCore but it is turned off here", and say +// so rather than silently omitting the option. +message ComputeProviderStatus { + // The provider type, matching ComputeProvider.type. This is the value a + // client sends back when configuring a scaling group, so it is the + // provider's identity, not a display name. + string type = 1; + + // Whether this Service will accept a ComputeConfig naming this provider. + // Depends both on the build and on Service configuration, the same way the + // per-capability booleans in GetSystemInfoResponse.Capabilities do. + bool enabled = 2; + + // How far along its rollout the provider is. Lets a client label a + // provider without shipping its own release-stage table, and lets the + // label change without a client release. + temporal.api.enums.v1.ComputeProviderReleaseStage release_stage = 3; +} diff --git a/temporal/api/enums/v1/compute.proto b/temporal/api/enums/v1/compute.proto new file mode 100644 index 000000000..d67e4525e --- /dev/null +++ b/temporal/api/enums/v1/compute.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package temporal.api.enums.v1; + +option go_package = "go.temporal.io/api/enums/v1;enums"; +option java_package = "io.temporal.api.enums.v1"; +option java_multiple_files = true; +option java_outer_classname = "ComputeProto"; +option ruby_package = "Temporalio::Api::Enums::V1"; +option csharp_namespace = "Temporalio.Api.Enums.V1"; + +// How far along its rollout a compute provider is. Clients use this to label a +// provider in a picker, and to decide whether to offer it prominently, so the +// label follows the server rather than being hardcoded per client. +enum ComputeProviderReleaseStage { + // Release stage is not specified. Clients should treat the provider as + // usable but unlabeled. + COMPUTE_PROVIDER_RELEASE_STAGE_UNSPECIFIED = 0; + // The provider is implemented but not yet ready for general use. Expect + // breaking changes. Clients should label it accordingly and may choose not + // to offer it by default. + COMPUTE_PROVIDER_RELEASE_STAGE_PRE_RELEASE = 1; + // The provider is available to all users but still gathering feedback, and + // may change in backwards-incompatible ways before becoming generally + // available. + COMPUTE_PROVIDER_RELEASE_STAGE_PUBLIC_PREVIEW = 2; + // The provider is generally available and covered by compatibility + // guarantees. + COMPUTE_PROVIDER_RELEASE_STAGE_GENERALLY_AVAILABLE = 3; +} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index de1c271cd..8853bd1bf 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -28,6 +28,7 @@ import "temporal/api/history/v1/message.proto"; import "temporal/api/workflow/v1/message.proto"; import "temporal/api/command/v1/message.proto"; import "temporal/api/compute/v1/config.proto"; +import "temporal/api/compute/v1/status.proto"; import "temporal/api/deployment/v1/message.proto"; import "temporal/api/failure/v1/message.proto"; import "temporal/api/filter/v1/message.proto"; @@ -1340,6 +1341,18 @@ message GetSystemInfoResponse { // All capabilities the system supports. Capabilities capabilities = 2; + // The compute providers this Service knows about, whether each is enabled + // here, and how far along its rollout each one is. + // + // This supersedes adding a boolean to Capabilities per compute provider. + // A boolean answers only "is this one provider usable", so every new + // provider costs a proto field, an api release, and a server release + // before a client can even gate on it, and it carries no release stage, + // leaving each client to hardcode its own. A repeated message lets a + // Service add a provider without a proto change, and lets a provider move + // from pre-release to generally available without a client release. + repeated temporal.api.compute.v1.ComputeProviderStatus compute_providers = 3; + // System capability details. message Capabilities { // True if signal and query headers are supported. @@ -1392,6 +1405,13 @@ message GetSystemInfoResponse { // True if the server supports the Cloud Run compute provider for // server-scaled deployments. Dependent on server version and the // provider being enabled via server configuration. + // + // Superseded by GetSystemInfoResponse.compute_providers, which reports + // every provider and its release stage rather than one boolean per + // provider. Retained for wire compatibility with clients that already + // read it; a Service setting this should also report the equivalent + // entry in compute_providers. No further per-provider booleans should + // be added here. bool server_scaled_provider_cloud_run = 13; } From d42cb3a5c48d0ca96e4042ee258a86a1fa2bb56a Mon Sep 17 00:00:00 2001 From: Ross Nelson Date: Tue, 8 Sep 2026 17:03:53 -0400 Subject: [PATCH 2/4] Regenerate OpenAPI specs for ComputeProviderStatus --- openapi/openapiv2.json | 39 +++++++++++++++++++++++++++- openapi/openapiv3.yaml | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index bb5acc172..3b9b9a2da 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -15074,6 +15074,35 @@ }, "description": "ComputeProvider stores information used by a worker control plane controller\nto respond to worker lifecycle events. For example, when a Task is received\non a TaskQueue that has no active pollers, a serverless worker lifecycle\ncontroller might need to invoke an AWS Lambda Function that itself ends up\ncalling the SDK's worker.New() function." }, + "v1ComputeProviderReleaseStage": { + "type": "string", + "enum": [ + "COMPUTE_PROVIDER_RELEASE_STAGE_UNSPECIFIED", + "COMPUTE_PROVIDER_RELEASE_STAGE_PRE_RELEASE", + "COMPUTE_PROVIDER_RELEASE_STAGE_PUBLIC_PREVIEW", + "COMPUTE_PROVIDER_RELEASE_STAGE_GENERALLY_AVAILABLE" + ], + "default": "COMPUTE_PROVIDER_RELEASE_STAGE_UNSPECIFIED", + "description": "How far along its rollout a compute provider is. Clients use this to label a\nprovider in a picker, and to decide whether to offer it prominently, so the\nlabel follows the server rather than being hardcoded per client.\n\n - COMPUTE_PROVIDER_RELEASE_STAGE_UNSPECIFIED: Release stage is not specified. Clients should treat the provider as\nusable but unlabeled.\n - COMPUTE_PROVIDER_RELEASE_STAGE_PRE_RELEASE: The provider is implemented but not yet ready for general use. Expect\nbreaking changes. Clients should label it accordingly and may choose not\nto offer it by default.\n - COMPUTE_PROVIDER_RELEASE_STAGE_PUBLIC_PREVIEW: The provider is available to all users but still gathering feedback, and\nmay change in backwards-incompatible ways before becoming generally\navailable.\n - COMPUTE_PROVIDER_RELEASE_STAGE_GENERALLY_AVAILABLE: The provider is generally available and covered by compatibility\nguarantees." + }, + "v1ComputeProviderStatus": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The provider type, matching ComputeProvider.type. This is the value a\nclient sends back when configuring a scaling group, so it is the\nprovider's identity, not a display name." + }, + "enabled": { + "type": "boolean", + "description": "Whether this Service will accept a ComputeConfig naming this provider.\nDepends both on the build and on Service configuration, the same way the\nper-capability booleans in GetSystemInfoResponse.Capabilities do." + }, + "releaseStage": { + "$ref": "#/definitions/v1ComputeProviderReleaseStage", + "description": "How far along its rollout the provider is. Lets a client label a\nprovider without shipping its own release-stage table, and lets the\nlabel change without a client release." + } + }, + "description": "ComputeProviderStatus describes one compute provider this Service knows\nabout, so a client can discover which providers exist and how to present\nthem without hardcoding a list of its own.\n\nA Service reports a provider it recognizes even when that provider is\ndisabled, so a client can tell \"this Service has never heard of AgentCore\"\napart from \"this Service knows AgentCore but it is turned off here\", and say\nso rather than silently omitting the option." + }, "v1ComputeScaler": { "type": "object", "properties": { @@ -16270,6 +16299,14 @@ "capabilities": { "$ref": "#/definitions/v1GetSystemInfoResponseCapabilities", "description": "All capabilities the system supports." + }, + "computeProviders": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ComputeProviderStatus" + }, + "description": "The compute providers this Service knows about, whether each is enabled\nhere, and how far along its rollout each one is.\n\nThis supersedes adding a boolean to Capabilities per compute provider.\nA boolean answers only \"is this one provider usable\", so every new\nprovider costs a proto field, an api release, and a server release\nbefore a client can even gate on it, and it carries no release stage,\nleaving each client to hardcode its own. A repeated message lets a\nService add a provider without a proto change, and lets a provider move\nfrom pre-release to generally available without a client release." } } }, @@ -16326,7 +16363,7 @@ }, "serverScaledProviderCloudRun": { "type": "boolean", - "description": "True if the server supports the Cloud Run compute provider for\nserver-scaled deployments. Dependent on server version and the\nprovider being enabled via server configuration." + "description": "True if the server supports the Cloud Run compute provider for\nserver-scaled deployments. Dependent on server version and the\nprovider being enabled via server configuration.\n\nSuperseded by GetSystemInfoResponse.compute_providers, which reports\nevery provider and its release stage rather than one boolean per\nprovider. Retained for wire compatibility with clients that already\nread it; a Service setting this should also report the equivalent\nentry in compute_providers. No further per-provider booleans should\nbe added here." } }, "description": "System capability details." diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 1d4c2cdc0..3d3a3fe21 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -11255,6 +11255,42 @@ components: on a TaskQueue that has no active pollers, a serverless worker lifecycle controller might need to invoke an AWS Lambda Function that itself ends up calling the SDK's worker.New() function. + ComputeProviderStatus: + type: object + properties: + type: + type: string + description: |- + The provider type, matching ComputeProvider.type. This is the value a + client sends back when configuring a scaling group, so it is the + provider's identity, not a display name. + enabled: + type: boolean + description: |- + Whether this Service will accept a ComputeConfig naming this provider. + Depends both on the build and on Service configuration, the same way the + per-capability booleans in GetSystemInfoResponse.Capabilities do. + releaseStage: + enum: + - COMPUTE_PROVIDER_RELEASE_STAGE_UNSPECIFIED + - COMPUTE_PROVIDER_RELEASE_STAGE_PRE_RELEASE + - COMPUTE_PROVIDER_RELEASE_STAGE_PUBLIC_PREVIEW + - COMPUTE_PROVIDER_RELEASE_STAGE_GENERALLY_AVAILABLE + type: string + description: |- + How far along its rollout the provider is. Lets a client label a + provider without shipping its own release-stage table, and lets the + label change without a client release. + format: enum + description: |- + ComputeProviderStatus describes one compute provider this Service knows + about, so a client can discover which providers exist and how to present + them without hardcoding a list of its own. + + A Service reports a provider it recognizes even when that provider is + disabled, so a client can tell "this Service has never heard of AgentCore" + apart from "this Service knows AgentCore but it is turned off here", and say + so rather than silently omitting the option. ComputeScaler: type: object properties: @@ -12588,6 +12624,21 @@ components: allOf: - $ref: '#/components/schemas/GetSystemInfoResponse_Capabilities' description: All capabilities the system supports. + computeProviders: + type: array + items: + $ref: '#/components/schemas/ComputeProviderStatus' + description: |- + The compute providers this Service knows about, whether each is enabled + here, and how far along its rollout each one is. + + This supersedes adding a boolean to Capabilities per compute provider. + A boolean answers only "is this one provider usable", so every new + provider costs a proto field, an api release, and a server release + before a client can even gate on it, and it carries no release stage, + leaving each client to hardcode its own. A repeated message lets a + Service add a provider without a proto change, and lets a provider move + from pre-release to generally available without a client release. GetSystemInfoResponse_Capabilities: type: object properties: @@ -12648,6 +12699,13 @@ components: True if the server supports the Cloud Run compute provider for server-scaled deployments. Dependent on server version and the provider being enabled via server configuration. + + Superseded by GetSystemInfoResponse.compute_providers, which reports + every provider and its release stage rather than one boolean per + provider. Retained for wire compatibility with clients that already + read it; a Service setting this should also report the equivalent + entry in compute_providers. No further per-provider booleans should + be added here. description: System capability details. GetWorkerBuildIdCompatibilityResponse: type: object From 43606455008e40bb57ef74d17f024832ddcee730 Mon Sep 17 00:00:00 2001 From: Ross Nelson Date: Tue, 8 Sep 2026 17:47:24 -0400 Subject: [PATCH 3/4] Move compute_providers to NamespaceInfo per review Quinn Klassen pointed out on #867 that GetSystemInfo is the wrong carrier: Cloud serves that endpoint as a fixed response at the reverse proxy layer, so nothing per-account or per-Namespace can reach a client through it, and suggested a Namespace-scoped surface instead. Both halves check out in the client code. temporalio/ui's fetchSystemInfo returns {} outright when isCloud, and cloud-ui synthesizes the whole systemInfo object client-side from account feature flags rather than calling the endpoint. Meanwhile cloud-ui already reads namespace.namespaceInfo.capabilities in standalone-nexus-guard.svelte, so NamespaceInfo demonstrably does reach Cloud. Namespace scope is also the correct scope on the merits, not just a way around the proxy. A compute provider is tied to the cloud its Namespace runs in, and cloud-ui already derives the provider list from the Namespace's RegionID_CloudProvider: an AWS Namespace offers Lambda and AgentCore, a GCP Namespace offers Cloud Run. One Service-wide list cannot say that. - NamespaceInfo.compute_providers = 9 - GetSystemInfoResponse otherwise reverted; the note on server_scaled_provider_cloud_run now records why no further per-provider booleans belong there - OpenAPI specs regenerated --- openapi/openapiv2.json | 18 ++++---- openapi/openapiv3.yaml | 43 ++++++++++--------- temporal/api/namespace/v1/message.proto | 14 ++++++ .../workflowservice/v1/request_response.proto | 25 +++-------- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 3b9b9a2da..506899ff1 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -16299,14 +16299,6 @@ "capabilities": { "$ref": "#/definitions/v1GetSystemInfoResponseCapabilities", "description": "All capabilities the system supports." - }, - "computeProviders": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ComputeProviderStatus" - }, - "description": "The compute providers this Service knows about, whether each is enabled\nhere, and how far along its rollout each one is.\n\nThis supersedes adding a boolean to Capabilities per compute provider.\nA boolean answers only \"is this one provider usable\", so every new\nprovider costs a proto field, an api release, and a server release\nbefore a client can even gate on it, and it carries no release stage,\nleaving each client to hardcode its own. A repeated message lets a\nService add a provider without a proto change, and lets a provider move\nfrom pre-release to generally available without a client release." } } }, @@ -16363,7 +16355,7 @@ }, "serverScaledProviderCloudRun": { "type": "boolean", - "description": "True if the server supports the Cloud Run compute provider for\nserver-scaled deployments. Dependent on server version and the\nprovider being enabled via server configuration.\n\nSuperseded by GetSystemInfoResponse.compute_providers, which reports\nevery provider and its release stage rather than one boolean per\nprovider. Retained for wire compatibility with clients that already\nread it; a Service setting this should also report the equivalent\nentry in compute_providers. No further per-provider booleans should\nbe added here." + "description": "True if the server supports the Cloud Run compute provider for\nserver-scaled deployments. Dependent on server version and the\nprovider being enabled via server configuration.\n\nSuperseded by NamespaceInfo.compute_providers, which reports every\nprovider and its release stage per Namespace rather than one boolean\nper provider for the whole Service. Retained for wire compatibility\nwith clients that already read it. No further per-provider booleans\nshould be added here: this response is served as a fixed payload in\nsome deployments, so it cannot express per-Namespace availability." } }, "description": "System capability details." @@ -17220,6 +17212,14 @@ "$ref": "#/definitions/NamespaceInfoLimits", "title": "Namespace configured limits" }, + "computeProviders": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ComputeProviderStatus" + }, + "description": "The compute providers available for server-scaled Worker Deployments in\nthis Namespace: which ones this Namespace can use, whether each is\ncurrently enabled, and how far along its rollout each one is.\n\nNamespace-scoped rather than Service-scoped for two reasons. Availability\ngenuinely varies per Namespace: a provider is tied to the cloud a\nNamespace runs in, so an AWS Namespace and a GCP Namespace do not offer\nthe same set, and managed deployments gate providers per account.\nGetSystemInfo cannot express either, and is served as a fixed payload\nahead of the Service in some deployments, so a per-provider boolean there\nis not reachable as a real signal." + }, "supportsSchedules": { "type": "boolean", "description": "Whether scheduled workflows are supported on this namespace. This is only needed\ntemporarily while the feature is experimental, so we can give it a high tag." diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 3d3a3fe21..718a6d0f7 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -12624,21 +12624,6 @@ components: allOf: - $ref: '#/components/schemas/GetSystemInfoResponse_Capabilities' description: All capabilities the system supports. - computeProviders: - type: array - items: - $ref: '#/components/schemas/ComputeProviderStatus' - description: |- - The compute providers this Service knows about, whether each is enabled - here, and how far along its rollout each one is. - - This supersedes adding a boolean to Capabilities per compute provider. - A boolean answers only "is this one provider usable", so every new - provider costs a proto field, an api release, and a server release - before a client can even gate on it, and it carries no release stage, - leaving each client to hardcode its own. A repeated message lets a - Service add a provider without a proto change, and lets a provider move - from pre-release to generally available without a client release. GetSystemInfoResponse_Capabilities: type: object properties: @@ -12700,12 +12685,12 @@ components: server-scaled deployments. Dependent on server version and the provider being enabled via server configuration. - Superseded by GetSystemInfoResponse.compute_providers, which reports - every provider and its release stage rather than one boolean per - provider. Retained for wire compatibility with clients that already - read it; a Service setting this should also report the equivalent - entry in compute_providers. No further per-provider booleans should - be added here. + Superseded by NamespaceInfo.compute_providers, which reports every + provider and its release stage per Namespace rather than one boolean + per provider for the whole Service. Retained for wire compatibility + with clients that already read it. No further per-provider booleans + should be added here: this response is served as a fixed payload in + some deployments, so it cannot express per-Namespace availability. description: System capability details. GetWorkerBuildIdCompatibilityResponse: type: object @@ -13538,6 +13523,22 @@ components: allOf: - $ref: '#/components/schemas/NamespaceInfo_Limits' description: Namespace configured limits + computeProviders: + type: array + items: + $ref: '#/components/schemas/ComputeProviderStatus' + description: |- + The compute providers available for server-scaled Worker Deployments in + this Namespace: which ones this Namespace can use, whether each is + currently enabled, and how far along its rollout each one is. + + Namespace-scoped rather than Service-scoped for two reasons. Availability + genuinely varies per Namespace: a provider is tied to the cloud a + Namespace runs in, so an AWS Namespace and a GCP Namespace do not offer + the same set, and managed deployments gate providers per account. + GetSystemInfo cannot express either, and is served as a fixed payload + ahead of the Service in some deployments, so a per-provider boolean there + is not reachable as a real signal. supportsSchedules: type: boolean description: |- diff --git a/temporal/api/namespace/v1/message.proto b/temporal/api/namespace/v1/message.proto index a80566458..d0db45a7e 100644 --- a/temporal/api/namespace/v1/message.proto +++ b/temporal/api/namespace/v1/message.proto @@ -12,6 +12,7 @@ option csharp_namespace = "Temporalio.Api.Namespace.V1"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; +import "temporal/api/compute/v1/status.proto"; import "temporal/api/enums/v1/namespace.proto"; @@ -83,6 +84,19 @@ message NamespaceInfo { int64 workflow_task_completion_size_limit_error = 3; } + // The compute providers available for server-scaled Worker Deployments in + // this Namespace: which ones this Namespace can use, whether each is + // currently enabled, and how far along its rollout each one is. + // + // Namespace-scoped rather than Service-scoped for two reasons. Availability + // genuinely varies per Namespace: a provider is tied to the cloud a + // Namespace runs in, so an AWS Namespace and a GCP Namespace do not offer + // the same set, and managed deployments gate providers per account. + // GetSystemInfo cannot express either, and is served as a fixed payload + // ahead of the Service in some deployments, so a per-provider boolean there + // is not reachable as a real signal. + repeated temporal.api.compute.v1.ComputeProviderStatus compute_providers = 9; + // Whether scheduled workflows are supported on this namespace. This is only needed // temporarily while the feature is experimental, so we can give it a high tag. bool supports_schedules = 100; diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 8853bd1bf..0a90dfbf2 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -28,7 +28,6 @@ import "temporal/api/history/v1/message.proto"; import "temporal/api/workflow/v1/message.proto"; import "temporal/api/command/v1/message.proto"; import "temporal/api/compute/v1/config.proto"; -import "temporal/api/compute/v1/status.proto"; import "temporal/api/deployment/v1/message.proto"; import "temporal/api/failure/v1/message.proto"; import "temporal/api/filter/v1/message.proto"; @@ -1341,18 +1340,6 @@ message GetSystemInfoResponse { // All capabilities the system supports. Capabilities capabilities = 2; - // The compute providers this Service knows about, whether each is enabled - // here, and how far along its rollout each one is. - // - // This supersedes adding a boolean to Capabilities per compute provider. - // A boolean answers only "is this one provider usable", so every new - // provider costs a proto field, an api release, and a server release - // before a client can even gate on it, and it carries no release stage, - // leaving each client to hardcode its own. A repeated message lets a - // Service add a provider without a proto change, and lets a provider move - // from pre-release to generally available without a client release. - repeated temporal.api.compute.v1.ComputeProviderStatus compute_providers = 3; - // System capability details. message Capabilities { // True if signal and query headers are supported. @@ -1406,12 +1393,12 @@ message GetSystemInfoResponse { // server-scaled deployments. Dependent on server version and the // provider being enabled via server configuration. // - // Superseded by GetSystemInfoResponse.compute_providers, which reports - // every provider and its release stage rather than one boolean per - // provider. Retained for wire compatibility with clients that already - // read it; a Service setting this should also report the equivalent - // entry in compute_providers. No further per-provider booleans should - // be added here. + // Superseded by NamespaceInfo.compute_providers, which reports every + // provider and its release stage per Namespace rather than one boolean + // per provider for the whole Service. Retained for wire compatibility + // with clients that already read it. No further per-provider booleans + // should be added here: this response is served as a fixed payload in + // some deployments, so it cannot express per-Namespace availability. bool server_scaled_provider_cloud_run = 13; } From 0958b7f2a427ff51eae148123d5ef14084daffcf Mon Sep 17 00:00:00 2001 From: Ross Nelson Date: Wed, 9 Sep 2026 12:43:55 -0400 Subject: [PATCH 4/4] Record why status is typed while provider config is not api#704 carried a typed ProviderDetailAWSLambda before #752 replaced it with an opaque Payload, so proposing a typed message here invites the obvious objection. The distinction is that provider config is open-ended and genuinely provider-specific, while provider status is uniform across every provider, and the comment now says so where a reviewer reads the message. Specs regenerated. --- openapi/openapiv2.json | 2 +- openapi/openapiv3.yaml | 8 ++++++++ temporal/api/compute/v1/status.proto | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 506899ff1..ce7cfd5cf 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -15101,7 +15101,7 @@ "description": "How far along its rollout the provider is. Lets a client label a\nprovider without shipping its own release-stage table, and lets the\nlabel change without a client release." } }, - "description": "ComputeProviderStatus describes one compute provider this Service knows\nabout, so a client can discover which providers exist and how to present\nthem without hardcoding a list of its own.\n\nA Service reports a provider it recognizes even when that provider is\ndisabled, so a client can tell \"this Service has never heard of AgentCore\"\napart from \"this Service knows AgentCore but it is turned off here\", and say\nso rather than silently omitting the option." + "description": "ComputeProviderStatus describes one compute provider this Service knows\nabout, so a client can discover which providers exist and how to present\nthem without hardcoding a list of its own.\n\nThis is typed where ComputeProvider.details is an opaque Payload, and the\ndifference is deliberate. Provider *config* is open-ended and genuinely\nprovider-specific: a Lambda ARN, a Cloud Run worker pool, and an AgentCore\nendpoint ARN share no shape, which is why an earlier typed\nProviderDetailAWSLambda gave way to a Payload. Provider *status* is uniform.\nEvery provider has an identity, an enabled bit, and a release stage, and none\nneeds a field the others do not.\n\nA Service reports a provider it recognizes even when that provider is\ndisabled, so a client can tell \"this Service has never heard of AgentCore\"\napart from \"this Service knows AgentCore but it is turned off here\", and say\nso rather than silently omitting the option." }, "v1ComputeScaler": { "type": "object", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 718a6d0f7..3cdf641a5 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -11287,6 +11287,14 @@ components: about, so a client can discover which providers exist and how to present them without hardcoding a list of its own. + This is typed where ComputeProvider.details is an opaque Payload, and the + difference is deliberate. Provider *config* is open-ended and genuinely + provider-specific: a Lambda ARN, a Cloud Run worker pool, and an AgentCore + endpoint ARN share no shape, which is why an earlier typed + ProviderDetailAWSLambda gave way to a Payload. Provider *status* is uniform. + Every provider has an identity, an enabled bit, and a release stage, and none + needs a field the others do not. + A Service reports a provider it recognizes even when that provider is disabled, so a client can tell "this Service has never heard of AgentCore" apart from "this Service knows AgentCore but it is turned off here", and say diff --git a/temporal/api/compute/v1/status.proto b/temporal/api/compute/v1/status.proto index 264b8faef..af660272c 100644 --- a/temporal/api/compute/v1/status.proto +++ b/temporal/api/compute/v1/status.proto @@ -15,6 +15,14 @@ import "temporal/api/enums/v1/compute.proto"; // about, so a client can discover which providers exist and how to present // them without hardcoding a list of its own. // +// This is typed where ComputeProvider.details is an opaque Payload, and the +// difference is deliberate. Provider *config* is open-ended and genuinely +// provider-specific: a Lambda ARN, a Cloud Run worker pool, and an AgentCore +// endpoint ARN share no shape, which is why an earlier typed +// ProviderDetailAWSLambda gave way to a Payload. Provider *status* is uniform. +// Every provider has an identity, an enabled bit, and a release stage, and none +// needs a field the others do not. +// // A Service reports a provider it recognizes even when that provider is // disabled, so a client can tell "this Service has never heard of AgentCore" // apart from "this Service knows AgentCore but it is turned off here", and say