6.4 KiB
Move RawWorkflowPlan to wf_api.models
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Extract RawWorkflowPlan from wf_mcp.models to canonical wf_api.models, keeping a compatibility shim in wf_mcp.models.
Architecture: RawWorkflowPlan is a standalone Pydantic model with no dependencies on other wf_mcp.models definitions. It depends only on pydantic and wf_core (Edge, InputBinding, Step). This makes it safe to move without entanglement. The wf_mcp.models module will re-export from wf_api.models as a shim.
Tech Stack: Python 3.14, Pydantic v2, pytest, ruff, basedpyright
Task 1: Create src/wf_api/models.py with RawWorkflowPlan
Files:
-
Create:
src/wf_api/models.py -
Step 1: Create the file with the model
from __future__ import annotations
from typing import Any
from pydantic import BaseModel, Field
from wf_core import Edge
from wf_core.models.steps import InputBinding, Step
class RawWorkflowPlan(BaseModel):
"""Raw authoring plan using the same graph step and edge models as core."""
name: str
input_schema: dict[str, Any]
state_schema: dict[str, Any]
output_schema: dict[str, Any]
outcomes: list[str] = Field(
default_factory=lambda: ["ok"],
description=(
"Declared public workflow outcomes. Legacy plans without this field "
"default to ok."
),
)
output: list[InputBinding] = Field(
default_factory=list,
description=(
"Optional root workflow output bindings. Sources read graph paths "
"such as state.result and targets write the public output payload."
),
)
start: str
nodes: list[Step]
edges: list[Edge]
- Step 2: Verify the file was created correctly
Run: python -c "from wf_api.models import RawWorkflowPlan; print(RawWorkflowPlan.__name__)"
Expected: RawWorkflowPlan
Task 2: Replace wf_mcp.models.RawWorkflowPlan definition with shim
Files:
-
Modify:
src/wf_mcp/models.py -
Step 1: Replace the RawWorkflowPlan class definition with a re-export
Replace the RawWorkflowPlan class block (lines 45-68) with:
# RawWorkflowPlan moved to wf_api.models; re-exported here for backward compat.
from wf_api.models import RawWorkflowPlan # noqa: F401
Keep the original import block for pydantic, Edge, InputBinding, Step — they are still used indirectly via the re-export. Actually, after removing the class definition, BaseModel, Field, Edge, InputBinding, Step are no longer needed by this file. Remove those imports if no other class in the file uses them.
Check: The remaining classes in wf_mcp/models.py are ConnectionConfig, AuthRecord, CatalogSnapshot, BrokerConfig, dump_catalog_snapshot. These use dataclass, field, Path, Any, CatalogNodeEntry, CatalogPromptEntry, CatalogResourceEntry. They do NOT use BaseModel, Field, Edge, InputBinding, Step.
So remove: from pydantic import BaseModel, Field, from wf_core import Edge, from wf_core.models.steps import InputBinding, Step.
- Step 2: Run ruff on the file
Run: uv run ruff check src/wf_mcp/models.py
Expected: no errors
- Step 3: Run basedpyright on the file
Run: uv run basedpyright --level error src/wf_mcp/models.py
Expected: no errors
Task 3: Update wf_mcp/__init__.py to import from shim
Files:
- Verify:
src/wf_mcp/__init__.py
No change needed — wf_mcp/__init__.py already imports RawWorkflowPlan from .models, and the shim re-exports it. Verify this still works.
- Step 1: Verify the import chain works
Run: python -c "from wf_mcp import RawWorkflowPlan; print(RawWorkflowPlan.__name__)"
Expected: RawWorkflowPlan
Task 4: Add focused tests
Files:
-
Create:
tests/wf_api/test_raw_workflow_plan_extraction.py -
Step 1: Write the tests
from __future__ import annotations
def test_canonical_import_from_wf_api_models() -> None:
from wf_api.models import RawWorkflowPlan
assert RawWorkflowPlan.__name__ == "RawWorkflowPlan"
def test_compat_import_from_wf_mcp_models() -> None:
from wf_mcp.models import RawWorkflowPlan as CompatPlan
assert CompatPlan.__name__ == "RawWorkflowPlan"
def test_canonical_and_compat_are_identical() -> None:
from wf_api.models import RawWorkflowPlan as Canonical
from wf_mcp.models import RawWorkflowPlan as Compat
assert Canonical is Compat
Note: The import direction rule is already covered by tests/wf_api/test_import_direction.py::test_wf_api_has_no_wf_mcp_imports. No need to duplicate.
- Step 2: Run the new tests
Run: uv run pytest tests/wf_api/test_raw_workflow_plan_extraction.py -v
Expected: all 3 PASS
Task 5: Update test imports to use canonical path
Files:
-
Modify:
tests/wf_mcp/service/conftest.py -
Modify:
tests/wf_mcp/workflow_surface/test_runs.py -
Step 1: Update
tests/wf_mcp/service/conftest.py
Change line 8 from:
from wf_mcp.models import AuthRecord, ConnectionConfig, RawWorkflowPlan
to:
from wf_api.models import RawWorkflowPlan
from wf_mcp.models import AuthRecord, ConnectionConfig
- Step 2: Update
tests/wf_mcp/workflow_surface/test_runs.py
Change line 32 from:
from wf_mcp.models import RawWorkflowPlan
to:
from wf_api.models import RawWorkflowPlan
- Step 3: Run ruff on touched files
Run: uv run ruff check tests/wf_mcp/service/conftest.py tests/wf_mcp/workflow_surface/test_runs.py
Expected: no errors
- Step 4: Run basedpyright on touched files
Run: uv run basedpyright --level error tests/wf_mcp/service/conftest.py tests/wf_mcp/workflow_surface/test_runs.py
Expected: no errors
Task 6: Run full test suite and verify
- Step 1: Run pytest
Run: uv run pytest -q
Expected: all tests pass
- Step 2: Run ruff on all touched files
Run: uv run ruff check src/wf_api/models.py src/wf_mcp/models.py src/wf_mcp/__init__.py tests/wf_api/test_raw_workflow_plan_extraction.py tests/wf_mcp/service/conftest.py tests/wf_mcp/workflow_surface/test_runs.py
Expected: no errors
- Step 3: Run basedpyright on touched files
Run: uv run basedpyright --level error src/wf_api/models.py src/wf_mcp/models.py
Expected: no errors