Files
lda-wf/docs/historical/superpowers/plans/2026-06-01-wf-api-slice-3a-refs-constants.md
T

12 KiB
Raw Blame History

wf_api Slice 3A: Refs And Constants Move Implementation Plan

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: Move the protocol-neutral workflow API refs and constants helpers from wf_mcp.workflow_surface into wf_api, while preserving old imports as compatibility shims.

Architecture: wf_api is now the canonical home for process-local workflow API helpers that are not MCP-specific. This slice moves only constants.py and refs.py because both are small and import only wf_artifacts / wf_platform. wf_mcp.workflow_surface.constants and wf_mcp.workflow_surface.refs remain thin re-export shims so existing imports keep working.

Tech Stack: Python 3.14+, Pydantic-backed refs from wf_artifacts and wf_platform, pytest, ruff, basedpyright.


Scope

In Scope

  • Create src/wf_api/constants.py.
  • Create src/wf_api/refs.py.
  • Re-export the new helpers from src/wf_api/__init__.py.
  • Replace wf_mcp.workflow_surface.constants with a compatibility shim.
  • Replace wf_mcp.workflow_surface.refs with a compatibility shim.
  • Update src/wf_mcp/workflow_surface/handlers.py to import canonical helpers from wf_api.
  • Add/adjust tests for canonical imports and shim compatibility.
  • Keep wf_api free of wf_mcp imports.

Out Of Scope

  • Do not move models.py.
  • Do not move next_actions.py.
  • Do not move wrapper_hints.py.
  • Do not move run_lifecycle.py.
  • Do not move runtime_dependencies.py.
  • Do not move saved_subgraphs.py.
  • Do not rename WorkflowSurfaceHandlers.
  • Do not change public payloads, tool names, command names, or parsing behavior.

File Structure

New Canonical Files

File Responsibility
src/wf_api/constants.py Canonical workflow API literals used by draft/helper code.
src/wf_api/refs.py Canonical parser for workflow-surface capability IDs.

Compatibility Shims

File Responsibility
src/wf_mcp/workflow_surface/constants.py Re-export constants from wf_api.constants; no local logic.
src/wf_mcp/workflow_surface/refs.py Re-export refs from wf_api.refs; no local logic.

Modified Consumers

File Change
src/wf_api/__init__.py Re-export moved helpers.
src/wf_mcp/workflow_surface/handlers.py Import constants and parser from wf_api.
tests/wf_mcp/test_workflow_surface_refs.py Keep shim compatibility tests and add canonical import tests.
tests/wf_api/test_import_direction.py Existing guard should continue to pass.

Task 1: Add Canonical wf_api.constants

Files:

  • Create: src/wf_api/constants.py

  • Step 1: Create src/wf_api/constants.py

Write this exact file:

"""Protocol-neutral workflow API literals used by draft/helper code."""

DEFAULT_CALL_STEP_ID = "call"
DEFAULT_ERROR_STEP_ID = "tool_error"
DEFAULT_OK_OUTCOME = "ok"
DEFAULT_ERROR_OUTCOME = "error"
RUNTIME_ERROR_CAPABILITY = "wf.std.runtime_error"

__all__ = [
    "DEFAULT_CALL_STEP_ID",
    "DEFAULT_ERROR_OUTCOME",
    "DEFAULT_ERROR_STEP_ID",
    "DEFAULT_OK_OUTCOME",
    "RUNTIME_ERROR_CAPABILITY",
]
  • Step 2: Run import smoke check

Run:

uv run python -c "from wf_api.constants import DEFAULT_CALL_STEP_ID, RUNTIME_ERROR_CAPABILITY; print(DEFAULT_CALL_STEP_ID, RUNTIME_ERROR_CAPABILITY)"

Expected output:

call wf.std.runtime_error

Task 2: Add Canonical wf_api.refs

Files:

  • Create: src/wf_api/refs.py

  • Step 1: Create src/wf_api/refs.py

Write this exact file:

from __future__ import annotations

from typing import Any, TypeAlias

from wf_artifacts import WorkflowCapabilityRef
from wf_platform import CapabilityRef

WorkflowSurfaceCapabilityId: TypeAlias = CapabilityRef | WorkflowCapabilityRef


def parse_workflow_surface_capability_id(
    value: str | dict[str, Any],
) -> WorkflowSurfaceCapabilityId:
    """Parse a workflow API capability id into its real domain ref.

    API callers still pass strings at protocol boundaries. Internally,
    workflow-facing capability ids are either live source capabilities or saved
    wrapper artifacts, so this parser avoids inventing a third identifier model.
    """
    if isinstance(value, dict):
        if "artifact_id" in value and "version" in value:
            return WorkflowCapabilityRef._validate(value)
        return CapabilityRef._validate(value)

    try:
        return WorkflowCapabilityRef.parse(value)
    except ValueError:
        return CapabilityRef.parse(value)
  • Step 2: Run import smoke check

Run:

uv run python -c "from wf_api.refs import parse_workflow_surface_capability_id; print(parse_workflow_surface_capability_id('workflow.echo_wrapper.v2'))"

Expected output:

workflow.echo_wrapper.v2

Task 3: Re-export Helpers From wf_api

Files:

  • Modify: src/wf_api/__init__.py

  • Step 1: Update imports and __all__

Change src/wf_api/__init__.py to include these imports:

from .constants import (
    DEFAULT_CALL_STEP_ID,
    DEFAULT_ERROR_OUTCOME,
    DEFAULT_ERROR_STEP_ID,
    DEFAULT_OK_OUTCOME,
    RUNTIME_ERROR_CAPABILITY,
)
from .refs import WorkflowSurfaceCapabilityId, parse_workflow_surface_capability_id

Ensure __all__ includes:

__all__ = [
    "DEFAULT_CALL_STEP_ID",
    "DEFAULT_ERROR_OUTCOME",
    "DEFAULT_ERROR_STEP_ID",
    "DEFAULT_OK_OUTCOME",
    "RUNTIME_ERROR_CAPABILITY",
    "TraceRange",
    "WorkflowApi",
    "WorkflowApiBackend",
    "WorkflowSurfaceCapabilityId",
    "parse_workflow_surface_capability_id",
]
  • Step 2: Run import smoke check

Run:

uv run python -c "from wf_api import DEFAULT_OK_OUTCOME, parse_workflow_surface_capability_id; print(DEFAULT_OK_OUTCOME, parse_workflow_surface_capability_id('demo.personal.echo_tool'))"

Expected output:

ok demo.personal.echo_tool

Task 4: Convert Old Workflow-Surface Modules To Shims

Files:

  • Modify: src/wf_mcp/workflow_surface/constants.py

  • Modify: src/wf_mcp/workflow_surface/refs.py

  • Step 1: Replace src/wf_mcp/workflow_surface/constants.py

Replace the file with this shim:

"""Compatibility shim for workflow API constants.

New code should import these literals from `wf_api.constants`. This module stays
so older MCP workflow-surface imports keep working during extraction.
"""

from wf_api.constants import (
    DEFAULT_CALL_STEP_ID,
    DEFAULT_ERROR_OUTCOME,
    DEFAULT_ERROR_STEP_ID,
    DEFAULT_OK_OUTCOME,
    RUNTIME_ERROR_CAPABILITY,
)

__all__ = [
    "DEFAULT_CALL_STEP_ID",
    "DEFAULT_ERROR_OUTCOME",
    "DEFAULT_ERROR_STEP_ID",
    "DEFAULT_OK_OUTCOME",
    "RUNTIME_ERROR_CAPABILITY",
]
  • Step 2: Replace src/wf_mcp/workflow_surface/refs.py

Replace the file with this shim:

"""Compatibility shim for workflow API capability refs.

New code should import from `wf_api.refs`. This module stays so older MCP
workflow-surface imports keep working during extraction.
"""

from wf_api.refs import (
    WorkflowSurfaceCapabilityId,
    parse_workflow_surface_capability_id,
)

__all__ = [
    "WorkflowSurfaceCapabilityId",
    "parse_workflow_surface_capability_id",
]
  • Step 3: Run shim import smoke check

Run:

uv run python -c "from wf_mcp.workflow_surface.constants import DEFAULT_CALL_STEP_ID; from wf_mcp.workflow_surface.refs import parse_workflow_surface_capability_id; print(DEFAULT_CALL_STEP_ID, parse_workflow_surface_capability_id('workflow.echo_wrapper.v2'))"

Expected output:

call workflow.echo_wrapper.v2

Task 5: Update Canonical Imports In WorkflowSurfaceHandlers

Files:

  • Modify: src/wf_mcp/workflow_surface/handlers.py

  • Step 1: Change constants import

Replace:

from .constants import (
    DEFAULT_CALL_STEP_ID,
    DEFAULT_ERROR_OUTCOME,
    DEFAULT_ERROR_STEP_ID,
    DEFAULT_OK_OUTCOME,
    RUNTIME_ERROR_CAPABILITY,
)

with:

from wf_api.constants import (
    DEFAULT_CALL_STEP_ID,
    DEFAULT_ERROR_OUTCOME,
    DEFAULT_ERROR_STEP_ID,
    DEFAULT_OK_OUTCOME,
    RUNTIME_ERROR_CAPABILITY,
)
  • Step 2: Change refs import

Replace:

from .refs import parse_workflow_surface_capability_id

with:

from wf_api.refs import parse_workflow_surface_capability_id
  • Step 3: Run import smoke check

Run:

uv run python -c "from wf_mcp.workflow_surface.handlers import WorkflowSurfaceHandlers; print(WorkflowSurfaceHandlers.__name__)"

Expected output:

WorkflowSurfaceHandlers

Task 6: Update Ref Tests For Canonical And Shim Imports

Files:

  • Modify: tests/wf_mcp/test_workflow_surface_refs.py

  • Step 1: Update imports

Change the top imports to:

from wf_api.refs import parse_workflow_surface_capability_id
from wf_artifacts import WorkflowCapabilityRef
from wf_mcp.workflow_surface.refs import (
    parse_workflow_surface_capability_id as parse_workflow_surface_capability_id_shim,
)
from wf_platform import CapabilityRef
  • Step 2: Add shim compatibility test

Append this test to the file:

def test_workflow_surface_refs_shim_reexports_canonical_parser() -> None:
    assert parse_workflow_surface_capability_id_shim is parse_workflow_surface_capability_id
  • Step 3: Add constants shim compatibility test

Append this test to the file:

def test_workflow_surface_constants_shim_reexports_canonical_literals() -> None:
    from wf_api.constants import DEFAULT_CALL_STEP_ID
    from wf_mcp.workflow_surface.constants import (
        DEFAULT_CALL_STEP_ID as DEFAULT_CALL_STEP_ID_SHIM,
    )

    assert DEFAULT_CALL_STEP_ID_SHIM == DEFAULT_CALL_STEP_ID
  • Step 4: Run focused tests

Run:

uv run pytest tests/wf_mcp/test_workflow_surface_refs.py tests/wf_api/test_import_direction.py -q

Expected: all tests pass.


Task 7: Search For Remaining Canonical Import Opportunities

Files:

  • Inspect only unless the search finds new low-risk direct consumers.

  • Step 1: Search old imports

Run:

rg -n "from \\.constants|from \\.refs|from wf_mcp\\.workflow_surface\\.(constants|refs)" src tests

Expected remaining matches:

src/wf_mcp/workflow_surface/constants.py
src/wf_mcp/workflow_surface/refs.py
tests/wf_mcp/test_workflow_surface_refs.py

If any other production module imports the old paths, update it to import from wf_api.constants or wf_api.refs.

  • Step 2: Search for accidental wf_api -> wf_mcp imports

Run:

rg -n "wf_mcp" src/wf_api tests/wf_api

Expected matches only in test text/docstrings for the import-direction guard, not in src/wf_api/*.py.


Task 8: Verification

  • Step 1: Run focused tests
uv run pytest tests/wf_api tests/wf_mcp/test_workflow_surface_refs.py tests/wf_mcp/workflow_surface -q

Expected: all pass.

  • Step 2: Run CLI context smoke tests
uv run pytest tests/wf_cli/test_context.py -q

Expected: pass.

  • Step 3: Run ruff on touched files
uv run ruff check src/wf_api src/wf_mcp/workflow_surface/constants.py src/wf_mcp/workflow_surface/refs.py src/wf_mcp/workflow_surface/handlers.py tests/wf_mcp/test_workflow_surface_refs.py tests/wf_api

Expected: all checks pass.

  • Step 4: Run basedpyright on touched files
uv run basedpyright --level error src/wf_api src/wf_mcp/workflow_surface/constants.py src/wf_mcp/workflow_surface/refs.py src/wf_mcp/workflow_surface/handlers.py tests/wf_mcp/test_workflow_surface_refs.py tests/wf_api

Expected: 0 errors.

  • Step 5: Optional full suite

Run this if time allows:

uv run pytest -q

Expected: full suite passes with the projects existing skipped/xfailed counts.


Self-Review Checklist

  • wf_api.constants imports no wf_mcp.
  • wf_api.refs imports no wf_mcp.
  • Old wf_mcp.workflow_surface.constants import path still works.
  • Old wf_mcp.workflow_surface.refs import path still works.
  • WorkflowSurfaceHandlers imports the canonical wf_api helpers.
  • No public payload shape changed.
  • No behavior changed.
  • No other workflow-surface helper moved in this slice.