diff --git a/contracts/workflow-api.manifest.json b/contracts/workflow-api.manifest.json index fff50a0a..1a5ea5ec 100644 --- a/contracts/workflow-api.manifest.json +++ b/contracts/workflow-api.manifest.json @@ -9065,6 +9065,10 @@ "required": false, "schema": { "default": "skip", + "enum": [ + "skip", + "parallel" + ], "type": "string" } }, @@ -9073,6 +9077,10 @@ "required": false, "schema": { "default": "skip", + "enum": [ + "skip", + "latest" + ], "type": "string" } }, @@ -9404,6 +9412,10 @@ "schema": { "anyOf": [ { + "enum": [ + "skip", + "parallel" + ], "type": "string" }, { @@ -9419,6 +9431,10 @@ "schema": { "anyOf": [ { + "enum": [ + "skip", + "latest" + ], "type": "string" }, { @@ -9434,6 +9450,7 @@ "schema": { "anyOf": [ { + "minimum": 1, "type": "integer" }, { @@ -9449,6 +9466,7 @@ "schema": { "anyOf": [ { + "minimum": 0, "type": "number" }, { @@ -9464,6 +9482,7 @@ "schema": { "anyOf": [ { + "minimum": 1, "type": "integer" }, { diff --git a/src/wf_api/surface.py b/src/wf_api/surface.py index 708783f5..72e4dc65 100644 --- a/src/wf_api/surface.py +++ b/src/wf_api/surface.py @@ -6,6 +6,7 @@ from typing import Any, Literal, Protocol, overload from wf_artifacts import ArtifactKind from wf_artifacts.drafts.models import DraftStep from wf_core.models.steps import InputBinding, OutputBinding, StepInputBinding +from wf_scheduling.models import MisfirePolicy, OverlapPolicy from .draft_authoring import RouteSource from .draft_updates import CapabilityStepUpdate @@ -561,8 +562,8 @@ class WorkflowScheduleSurface(Protocol): deployment_id: str, trigger: dict[str, Any], input_bindings: list[dict[str, Any]] | None = None, - overlap: str = "skip", - misfire: str = "skip", + overlap: OverlapPolicy = "skip", + misfire: MisfirePolicy = "skip", max_active_runs: int = 1, lateness_allowance_s: float = 60.0, max_steps: int | None = None, @@ -589,8 +590,8 @@ class WorkflowScheduleSurface(Protocol): deployment_id: str | None = None, trigger: dict[str, Any] | None = None, input_bindings: list[dict[str, Any]] | None = None, - overlap: str | None = None, - misfire: str | None = None, + overlap: OverlapPolicy | None = None, + misfire: MisfirePolicy | None = None, max_active_runs: int | None = None, lateness_allowance_s: float | None = None, max_steps: int | None = None, diff --git a/src/wf_transport_rpc_http/models.py b/src/wf_transport_rpc_http/models.py index 4d9f45cd..525aa98d 100644 --- a/src/wf_transport_rpc_http/models.py +++ b/src/wf_transport_rpc_http/models.py @@ -8,6 +8,7 @@ from wf_api import CapabilityStepUpdate from wf_api.models import TraceRange from wf_artifacts.drafts.models import DraftStep from wf_core.models.steps import InputBinding, OutputBinding, StepInputBinding +from wf_scheduling.models import MisfirePolicy, OverlapPolicy class RpcParamsModel(BaseModel): @@ -467,8 +468,8 @@ class CreateScheduleParams(RpcParamsModel): deployment_id: str = Field(min_length=1) trigger: dict[str, Any] input_bindings: list[dict[str, Any]] = Field(default_factory=list) - overlap: str = "skip" - misfire: str = "skip" + overlap: OverlapPolicy = "skip" + misfire: MisfirePolicy = "skip" max_active_runs: int = Field(default=1, ge=1) lateness_allowance_s: float = Field(default=60.0, ge=0) max_steps: int | None = Field( @@ -496,8 +497,8 @@ class UpdateScheduleParams(RpcParamsModel): deployment_id: str | None = None trigger: dict[str, Any] | None = None input_bindings: list[dict[str, Any]] | None = None - overlap: str | None = None - misfire: str | None = None + overlap: OverlapPolicy | None = None + misfire: MisfirePolicy | None = None max_active_runs: int | None = Field(default=None, ge=1) lateness_allowance_s: float | None = Field(default=None, ge=0) max_steps: int | None = Field(default=None, ge=1, strict=True) diff --git a/tests/wf_transport_rpc_http/test_rpc_models.py b/tests/wf_transport_rpc_http/test_rpc_models.py index 610563b7..2fd8909d 100644 --- a/tests/wf_transport_rpc_http/test_rpc_models.py +++ b/tests/wf_transport_rpc_http/test_rpc_models.py @@ -5,6 +5,7 @@ from pydantic import ValidationError from wf_core.models.steps import InputExpressionBinding from wf_transport_rpc_http.models import ( + CreateScheduleParams, InspectCapabilityParams, ListCapabilitiesParams, ReadRunTraceParams, @@ -94,6 +95,20 @@ def test_update_schedule_params_match_create_numeric_constraints() -> None: ) +def test_schedule_policy_params_reject_unknown_values() -> None: + with pytest.raises(ValidationError): + CreateScheduleParams( + schedule_id="schedule", + deployment_id="deployment", + trigger={"kind": "oneshot", "at": "2026-09-08T12:00:00+00:00"}, + overlap="queue", + ) + with pytest.raises(ValidationError): + UpdateScheduleParams( + schedule_id="schedule", expected_revision=1, misfire="replay" + ) + + def test_step_input_params_accept_composite_bindings_but_workflow_output_does_not() -> ( None ):