Files
lda-wf/docs/historical/superpowers/plans/2026-06-01-move-rawworkflowplan.md
T

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