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

504 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:
```python
"""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:
```powershell
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:
```text
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:
```python
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:
```powershell
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:
```text
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:
```python
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:
```python
__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:
```powershell
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:
```text
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:
```python
"""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:
```python
"""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:
```powershell
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:
```text
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:
```python
from .constants import (
DEFAULT_CALL_STEP_ID,
DEFAULT_ERROR_OUTCOME,
DEFAULT_ERROR_STEP_ID,
DEFAULT_OK_OUTCOME,
RUNTIME_ERROR_CAPABILITY,
)
```
with:
```python
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:
```python
from .refs import parse_workflow_surface_capability_id
```
with:
```python
from wf_api.refs import parse_workflow_surface_capability_id
```
- [ ] **Step 3: Run import smoke check**
Run:
```powershell
uv run python -c "from wf_mcp.workflow_surface.handlers import WorkflowSurfaceHandlers; print(WorkflowSurfaceHandlers.__name__)"
```
Expected output:
```text
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:
```python
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:
```python
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:
```python
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:
```powershell
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:
```powershell
rg -n "from \\.constants|from \\.refs|from wf_mcp\\.workflow_surface\\.(constants|refs)" src tests
```
Expected remaining matches:
```text
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:
```powershell
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**
```powershell
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**
```powershell
uv run pytest tests/wf_cli/test_context.py -q
```
Expected: pass.
- [ ] **Step 3: Run ruff on touched files**
```powershell
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**
```powershell
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:
```powershell
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.