docs
This commit is contained in:
@@ -37,6 +37,13 @@ implementation state.
|
|||||||
- Source inventory distinguishes external sources, local workflow-facing
|
- Source inventory distinguishes external sources, local workflow-facing
|
||||||
sources, docs/resources, and admin-only control surfaces.
|
sources, docs/resources, and admin-only control surfaces.
|
||||||
|
|
||||||
|
6. **Workflow API seam**
|
||||||
|
- `wf_api.WorkflowApi` is now the process-local application-facing workflow
|
||||||
|
API used by both CLI commands and MCP workflow tools.
|
||||||
|
- `wf_api` imports no `wf_mcp` modules. The current adapter,
|
||||||
|
`WfMcpWorkflowApiBackend`, still wraps the existing MCP service stack while
|
||||||
|
later slices extract protocol-neutral logic behind that seam.
|
||||||
|
|
||||||
## Runtime and Platform Roadmap
|
## Runtime and Platform Roadmap
|
||||||
|
|
||||||
- Scheduler foundation decision record:
|
- Scheduler foundation decision record:
|
||||||
@@ -99,6 +106,11 @@ implementation state.
|
|||||||
`wf.workflow.run_deployment` remains the dependable front door.
|
`wf.workflow.run_deployment` remains the dependable front door.
|
||||||
- **Dashboard/source controls**: future UI should consume the same source
|
- **Dashboard/source controls**: future UI should consume the same source
|
||||||
inventory and deployment metadata instead of reverse-engineering MCP tools.
|
inventory and deployment metadata instead of reverse-engineering MCP tools.
|
||||||
|
- **Workflow API extraction**: continue the staged extraction in
|
||||||
|
[wf_api extraction roadmap](./superpowers/plans/2026-06-01-wf-api-extraction-roadmap.md).
|
||||||
|
The next useful slice is naming/documentation cleanup around
|
||||||
|
`WorkflowSurfaceHandlers` versus `wf_api.WorkflowApi`, before moving helper
|
||||||
|
modules or splitting the large operation implementation.
|
||||||
|
|
||||||
Frame stress points remaining for native subgraphs and future fork/gather:
|
Frame stress points remaining for native subgraphs and future fork/gather:
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,16 @@
|
|||||||
|
|
||||||
**Architecture:** `wf_api` becomes the long-lived in-process application service layer. `wf_mcp`, `wf_cli`, and future HTTP/UI adapters call `wf_api`; `wf_api` must not import `wf_mcp`.
|
**Architecture:** `wf_api` becomes the long-lived in-process application service layer. `wf_mcp`, `wf_cli`, and future HTTP/UI adapters call `wf_api`; `wf_api` must not import `wf_mcp`.
|
||||||
|
|
||||||
**Current Constraint:** `WorkflowSurfaceHandlers` is large and currently depends on `WfMcpService`. The first slice fixes dependency direction only; later slices can split and rename once the boundary is correct.
|
**Current State:** Slice 1 introduced `wf_api.WorkflowApi`,
|
||||||
|
`wf_api.WorkflowApiBackend`, and `wf_mcp.broker.service.WfMcpWorkflowApiBackend`.
|
||||||
|
Both CLI and MCP workflow tools now call `WorkflowApi`; `wf_api` imports no
|
||||||
|
`wf_mcp` modules. `WorkflowSurfaceHandlers` still contains the existing
|
||||||
|
operation implementation and still depends on `WfMcpService`, but it is now
|
||||||
|
MCP-owned backend plumbing rather than the public application API.
|
||||||
|
|
||||||
|
**Current Constraint:** `WorkflowSurfaceHandlers` is large and still carries
|
||||||
|
most workflow-surface logic. Slice 1 fixed dependency direction only; later
|
||||||
|
slices can split and rename once the boundary is correct.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -74,48 +83,41 @@ does not import `wf_mcp`.
|
|||||||
- Do not change response payloads.
|
- Do not change response payloads.
|
||||||
- Do not change command/tool names.
|
- Do not change command/tool names.
|
||||||
|
|
||||||
### Shape
|
### Implemented Shape
|
||||||
|
|
||||||
```text
|
```text
|
||||||
src/wf_api/
|
src/wf_api/
|
||||||
__init__.py
|
__init__.py
|
||||||
backend.py # WorkflowApiBackend protocol
|
backend.py # WorkflowApiBackend high-level operation protocol
|
||||||
service.py # WorkflowApi, initially large
|
service.py # WorkflowApi thin delegating facade
|
||||||
|
|
||||||
src/wf_mcp/workflow_surface/
|
src/wf_mcp/workflow_surface/
|
||||||
handlers.py # compatibility alias or thin import shim
|
handlers.py # existing implementation; now backend plumbing
|
||||||
tools.py # MCP adapter; calls WorkflowApi
|
tools.py # MCP adapter; calls WorkflowApi
|
||||||
|
|
||||||
src/wf_mcp/broker/service/
|
src/wf_mcp/broker/service/
|
||||||
workflow_api_backend.py # WfMcpWorkflowApiBackend
|
workflow_api_backend.py # WfMcpWorkflowApiBackend
|
||||||
```
|
```
|
||||||
|
|
||||||
`WorkflowApiBackend` should expose only what `WorkflowApi` currently uses:
|
`WorkflowApiBackend` currently exposes high-level workflow operations that mirror
|
||||||
|
the old workflow surface (`list_capabilities`, `create_draft_workspace`, `run_deployment`,
|
||||||
|
and so on). That is intentionally not the final clean domain API. It keeps
|
||||||
|
behavior and payloads stable while introducing the dependency seam. Later slices
|
||||||
|
can replace selected `dict[str, Any]` method boundaries with stronger domain
|
||||||
|
models after callers are routed through `WorkflowApi`.
|
||||||
|
|
||||||
```python
|
Live source validation remains behind the MCP backend adapter because it touches
|
||||||
artifact_store
|
MCP connections, adapters, and auth. `wf_api` owns the operation name, but the
|
||||||
draft_workspace_store
|
current backend owns the live-check implementation.
|
||||||
run_store
|
|
||||||
capability_sources
|
|
||||||
get_qualified_spec(...)
|
|
||||||
record_event(...)
|
|
||||||
run_workflow_from_plan(...)
|
|
||||||
resume_workflow_from_plan(...)
|
|
||||||
workflow_artifact_catalog_entry(...)
|
|
||||||
```
|
|
||||||
|
|
||||||
Live source validation is the awkward part because it touches MCP connections,
|
|
||||||
adapters, and auth. In Slice 1, it can stay behind backend methods/callbacks
|
|
||||||
without making `wf_api` import `wf_mcp`.
|
|
||||||
|
|
||||||
### Success Criteria
|
### Success Criteria
|
||||||
|
|
||||||
- `wf_api` imports no `wf_mcp` modules.
|
- `wf_api` imports no `wf_mcp` modules. **Done.**
|
||||||
- `wf_cli` uses `WorkflowApi`.
|
- `wf_cli` uses `WorkflowApi`. **Done.**
|
||||||
- `wf_mcp.workflow_surface.tools` uses `WorkflowApi`.
|
- `wf_mcp.workflow_surface.tools` uses `WorkflowApi`. **Done.**
|
||||||
- Existing MCP workflow-surface tests pass.
|
- Existing MCP workflow-surface tests pass. **Done at implementation time.**
|
||||||
- Existing CLI tests pass.
|
- Existing CLI tests pass. **Done at implementation time.**
|
||||||
- Behavior and payloads are unchanged.
|
- Behavior and payloads are unchanged. **Intended and guarded by tests.**
|
||||||
|
|
||||||
## Slice 2: Stabilize API Names And Compatibility Shims
|
## Slice 2: Stabilize API Names And Compatibility Shims
|
||||||
|
|
||||||
@@ -123,10 +125,22 @@ without making `wf_api` import `wf_mcp`.
|
|||||||
|
|
||||||
Make naming honest without breaking callers.
|
Make naming honest without breaking callers.
|
||||||
|
|
||||||
### Likely Work
|
### Docs-First Current Slice
|
||||||
|
|
||||||
|
Before renames, document the new ownership:
|
||||||
|
|
||||||
|
- `wf_api.WorkflowApi` is the application-facing process-local API.
|
||||||
|
- `wf_api.WorkflowApiBackend` is the high-level backend protocol.
|
||||||
|
- `wf_mcp.broker.service.WfMcpWorkflowApiBackend` adapts the current MCP service
|
||||||
|
stack into the backend protocol.
|
||||||
|
- `wf_mcp.workflow_surface.WorkflowSurfaceHandlers` is legacy/internal
|
||||||
|
implementation plumbing. New adapter code should not treat it as the canonical
|
||||||
|
API.
|
||||||
|
|
||||||
|
### Later Likely Work
|
||||||
|
|
||||||
- Rename `WorkflowSurfaceHandlers` usage to `WorkflowApi` in tests and CLI code.
|
- Rename `WorkflowSurfaceHandlers` usage to `WorkflowApi` in tests and CLI code.
|
||||||
- Keep a temporary import shim:
|
- If a class rename is chosen, keep a temporary import shim:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from wf_api import WorkflowApi as WorkflowSurfaceHandlers
|
from wf_api import WorkflowApi as WorkflowSurfaceHandlers
|
||||||
@@ -339,21 +353,13 @@ async def start_run(...):
|
|||||||
5. Should `wf_cli` stop importing `wf_mcp` after Slice 1?
|
5. Should `wf_cli` stop importing `wf_mcp` after Slice 1?
|
||||||
- Not fully. It may still use `wf_mcp` config/service construction until store/config extraction happens.
|
- Not fully. It may still use `wf_mcp` config/service construction until store/config extraction happens.
|
||||||
|
|
||||||
## Immediate Next Plan
|
## Immediate Next Plan Status
|
||||||
|
|
||||||
Write a focused implementation plan for Slice 1 only:
|
Slice 1 implementation plan exists and was executed:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
docs/superpowers/plans/YYYY-MM-DD-wf-api-slice-1-dependency-direction.md
|
docs/superpowers/plans/2026-06-01-wf-api-slice-1-dependency-direction.md
|
||||||
```
|
```
|
||||||
|
|
||||||
That plan should be code-level and deterministic:
|
The next implementation plan should cover Slice 2 only. Prefer docs and
|
||||||
|
compatibility naming first; do not move helper modules until Slice 3.
|
||||||
- add `wf_api.backend`
|
|
||||||
- add `wf_api.service`
|
|
||||||
- add `WfMcpWorkflowApiBackend`
|
|
||||||
- update CLI/MCP construction
|
|
||||||
- keep compatibility import
|
|
||||||
- run focused MCP workflow-surface and CLI tests
|
|
||||||
|
|
||||||
Do not include Slice 2+ work in that implementation plan.
|
|
||||||
|
|||||||
@@ -0,0 +1,496 @@
|
|||||||
|
# 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 project’s 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.
|
||||||
@@ -26,6 +26,8 @@ relevant concern package directly.
|
|||||||
|
|
||||||
## Dependency Rules
|
## Dependency Rules
|
||||||
|
|
||||||
|
- `wf_api` is the process-local workflow application API. `wf_mcp` may import
|
||||||
|
and adapt it; `wf_api` must not import `wf_mcp`.
|
||||||
- `wf_mcp.sdk` should not import `wf_core` or `wf_authoring`.
|
- `wf_mcp.sdk` should not import `wf_core` or `wf_authoring`.
|
||||||
- `wf_mcp.proxy` should not import `wf_mcp.workflow`.
|
- `wf_mcp.proxy` should not import `wf_mcp.workflow`.
|
||||||
- `wf_mcp.workflow` is the only layer that converts MCP capabilities into node specs.
|
- `wf_mcp.workflow` is the only layer that converts MCP capabilities into node specs.
|
||||||
@@ -34,6 +36,30 @@ relevant concern package directly.
|
|||||||
- `wf_mcp.shared` should stay pure and should not import other `wf_mcp` concern packages.
|
- `wf_mcp.shared` should stay pure and should not import other `wf_mcp` concern packages.
|
||||||
- Root compatibility shims should stay thin: import and re-export only.
|
- Root compatibility shims should stay thin: import and re-export only.
|
||||||
|
|
||||||
|
## Workflow API Boundary
|
||||||
|
|
||||||
|
Workflow lifecycle operations now have a protocol-neutral front door:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wf_cli ─┐
|
||||||
|
├──> wf_api.WorkflowApi ───> WorkflowApiBackend
|
||||||
|
wf_mcp ─┘
|
||||||
|
```
|
||||||
|
|
||||||
|
The current backend is `wf_mcp.broker.service.WfMcpWorkflowApiBackend`, which
|
||||||
|
wraps the existing `wf_mcp.workflow_surface.WorkflowSurfaceHandlers`. That
|
||||||
|
handler class still contains most workflow-surface logic and still depends on
|
||||||
|
`WfMcpService`; it is kept for compatibility and incremental extraction.
|
||||||
|
|
||||||
|
New code should treat `wf_api.WorkflowApi` as the application-facing API. Do not
|
||||||
|
add new callers that import `WorkflowSurfaceHandlers` directly unless they are
|
||||||
|
inside the MCP backend adapter or compatibility tests.
|
||||||
|
|
||||||
|
This is a dependency-direction cleanup, not a full domain split. Most API
|
||||||
|
methods still mirror the old workflow-surface payloads and return
|
||||||
|
`dict[str, Any]`. Stronger domain models and helper-module moves belong in later
|
||||||
|
`wf_api` extraction slices.
|
||||||
|
|
||||||
## Broker Catalogs
|
## Broker Catalogs
|
||||||
|
|
||||||
The broker keeps two related catalog views:
|
The broker keeps two related catalog views:
|
||||||
|
|||||||
Reference in New Issue
Block a user