fix: address semantic draft review nits
This commit is contained in:
@@ -4,6 +4,10 @@ from collections.abc import Sequence
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from wf_artifacts.draft_workspaces.models import (
|
||||
WorkflowDraftWorkspace,
|
||||
summarize_draft_workspace,
|
||||
)
|
||||
from wf_core.models.steps import (
|
||||
InputBinding,
|
||||
OutputBinding,
|
||||
@@ -45,6 +49,31 @@ class WorkflowDraftAuthoringApi:
|
||||
self.context = context
|
||||
self.drafts = drafts
|
||||
|
||||
def _workspace_if_revision_matches(
|
||||
self,
|
||||
*,
|
||||
workspace_id: str,
|
||||
revision: int,
|
||||
) -> WorkflowDraftWorkspace | dict[str, Any]:
|
||||
"""Load a workspace for no-op edits while still enforcing optimistic locks."""
|
||||
workspace = self.drafts._draft_store().get_workspace(workspace_id)
|
||||
if workspace.revision == revision:
|
||||
return workspace
|
||||
return {
|
||||
**summarize_draft_workspace(workspace),
|
||||
"status": "conflict",
|
||||
"diagnostics": [
|
||||
{
|
||||
"code": "revision_conflict",
|
||||
"path": "revision",
|
||||
"message": (
|
||||
f"workspace {workspace.id!r} is at revision "
|
||||
f"{workspace.revision}, not {revision}"
|
||||
),
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
def _outcomes_for_capability(self, qualified_name: str) -> tuple[str, ...] | None:
|
||||
try:
|
||||
spec = self.context.specs.get_qualified_spec(qualified_name)
|
||||
@@ -317,9 +346,13 @@ class WorkflowDraftAuthoringApi:
|
||||
raise ValueError(f"routes for step {step_id!r} must be an object")
|
||||
merged = {**existing, **routes}
|
||||
if merged == existing:
|
||||
return await self.drafts.get_draft_workspace(
|
||||
checked = self._workspace_if_revision_matches(
|
||||
workspace_id=workspace_id,
|
||||
revision=revision,
|
||||
)
|
||||
if isinstance(checked, dict):
|
||||
return checked
|
||||
return summarize_draft_workspace(checked)
|
||||
return await self.drafts.patch_draft_workspace(
|
||||
workspace_id=workspace_id,
|
||||
revision=revision,
|
||||
@@ -342,9 +375,13 @@ class WorkflowDraftAuthoringApi:
|
||||
) -> dict[str, Any]:
|
||||
"""Update the target for multiple (step, outcome) pairs atomically."""
|
||||
if not branches:
|
||||
return await self.drafts.get_draft_workspace(
|
||||
checked = self._workspace_if_revision_matches(
|
||||
workspace_id=workspace_id,
|
||||
revision=revision,
|
||||
)
|
||||
if isinstance(checked, dict):
|
||||
return checked
|
||||
return summarize_draft_workspace(checked)
|
||||
workspace = self.drafts._draft_store().get_workspace(workspace_id)
|
||||
draft_routes = workspace.draft.get("routes", {})
|
||||
if not isinstance(draft_routes, dict):
|
||||
@@ -374,9 +411,13 @@ class WorkflowDraftAuthoringApi:
|
||||
}
|
||||
)
|
||||
if not patch:
|
||||
return await self.drafts.get_draft_workspace(
|
||||
checked = self._workspace_if_revision_matches(
|
||||
workspace_id=workspace_id,
|
||||
revision=revision,
|
||||
)
|
||||
if isinstance(checked, dict):
|
||||
return checked
|
||||
return summarize_draft_workspace(checked)
|
||||
return await self.drafts.patch_draft_workspace(
|
||||
workspace_id=workspace_id,
|
||||
revision=revision,
|
||||
|
||||
@@ -53,13 +53,13 @@ def state_root_field(value: str) -> str:
|
||||
|
||||
|
||||
def _local_path_payload(value: str) -> str:
|
||||
return LocalPath._serialize(LocalPath.parse(value))
|
||||
return str(LocalPath.parse(value))
|
||||
|
||||
|
||||
def _graph_path_payload(value: str | GraphSourcePath) -> str:
|
||||
path = value if isinstance(value, GraphSourcePath) else GraphSourcePath.parse(value)
|
||||
return GraphSourcePath._serialize(path)
|
||||
return str(path)
|
||||
|
||||
|
||||
def _state_path_payload(value: str) -> str:
|
||||
return StatePath._serialize(StatePath.parse(value))
|
||||
return str(StatePath.parse(value))
|
||||
|
||||
@@ -32,10 +32,15 @@ def project_output_property_to_state_schema(
|
||||
raise ValueError(f"output field {output_field!r} is not a JSON Schema object")
|
||||
|
||||
projected = deepcopy(state_schema)
|
||||
state_type = projected.get("type")
|
||||
if state_type is not None and state_type != "object":
|
||||
raise ValueError("state_schema must be an object schema")
|
||||
projected.setdefault("type", "object")
|
||||
properties = projected.setdefault("properties", {})
|
||||
if not isinstance(properties, dict):
|
||||
raise ValueError("state_schema.properties must be an object")
|
||||
if state_field in properties:
|
||||
raise ValueError(f"state field {state_field!r} already exists")
|
||||
properties[state_field] = deepcopy(output_property)
|
||||
|
||||
_merge_definition_block(projected, output_schema, "$defs")
|
||||
|
||||
@@ -8,7 +8,7 @@ from wf_artifacts import ArtifactKind
|
||||
from .artifacts import WorkflowArtifactApi
|
||||
from .capabilities import WorkflowCapabilityApi
|
||||
from .deployments import WorkflowDeploymentApi
|
||||
from .draft_authoring import WorkflowDraftAuthoringApi
|
||||
from .draft_authoring import DraftOutcomeRef, WorkflowDraftAuthoringApi
|
||||
from .drafts import WorkflowDraftApi
|
||||
from .models import RawWorkflowPlan
|
||||
from .operation_context import WorkflowOperationContext
|
||||
@@ -436,8 +436,6 @@ class WorkflowApi:
|
||||
branches: list[dict[str, str]],
|
||||
target: str,
|
||||
) -> dict[str, Any]:
|
||||
from .draft_authoring import DraftOutcomeRef
|
||||
|
||||
refs = [
|
||||
DraftOutcomeRef(step_id=b["step_id"], outcome=b["outcome"])
|
||||
for b in branches
|
||||
|
||||
Reference in New Issue
Block a user