Files
lda-wf/docs/historical/superpowers/plans/2026-06-27-draft-semantic-authoring-and-compile.md
T

15 KiB

Draft Semantic Authoring And Compile 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: Separate semantic draft authoring from workspace lifecycle, add branch and handle, make capability-step routing complete, and expose read-only stored-workspace compilation.

Architecture: WorkflowDraft remains the only stored authoring document. A new WorkflowDraftAuthoringApi resolves capability metadata and lowers semantic intent to one atomic patch through WorkflowDraftApi; the latter retains lifecycle, validation, compilation, low-level edits, and JSON Patch. Public CLI, RPC, and MCP surfaces remain unified through WorkflowApi.

Tech Stack: Python 3.14, Pydantic v2, JSON Patch, Typer, JSON-RPC, FastMCP, pytest, Ruff, basedpyright.

Prerequisite: Complete docs/historical/superpowers/plans/2026-06-27-canonical-toml-path-strings.md first.


Task 1: Extract The Semantic Authoring Service Without Behavior Changes

Files:

  • Create: src/wf_api/draft_authoring.py

  • Create: src/wf_api/draft_payloads.py

  • Modify: src/wf_api/drafts.py

  • Modify: src/wf_api/service.py

  • Test: tests/wf_api/test_drafts_service.py

  • Step 1: Add a facade delegation test

Add a focused test asserting WorkflowApi constructs a sibling authoring service and existing bind_output_to_state behavior still consumes one revision.

  • Step 2: Extract shared draft payload helpers

Move the existing _draft_step, _escape_json_pointer, _draft_input_bindings_payload, _draft_output_bindings_payload, and _state_root_field bodies unchanged into src/wf_api/draft_payloads.py. Rename them to draft_step, escape_json_pointer, input_bindings_payload, output_bindings_payload, and state_root_field, update both service imports, and add short docstrings. Do not change serialized behavior in this extraction.

  • Step 3: Introduce WorkflowDraftAuthoringApi

Use an explicit dependency on the lifecycle service:

class WorkflowDraftAuthoringApi:
    """Capability-aware semantic edits over revisioned workflow drafts."""

    def __init__(
        self,
        context: WorkflowOperationContext,
        drafts: WorkflowDraftApi,
    ) -> None:
        self.context = context
        self.drafts = drafts

Move create_minimal_draft_workspace, bind_output_to_state, and add_step_from_capability into this class. Each operation must call self.drafts.patch_draft_workspace or another public lifecycle method rather than accessing the store directly for mutation.

  • Step 4: Preserve the unified facade

In WorkflowApi.__init__:

self.drafts = WorkflowDraftApi(context)
self.draft_authoring = WorkflowDraftAuthoringApi(context, self.drafts)

Existing public delegates keep their names and forward semantic calls to self.draft_authoring.

  • Step 5: Run focused tests

Run: uv run pytest tests/wf_api/test_drafts_service.py -q

Expected: PASS with no public behavior change.

  • Step 6: Commit
git add src/wf_api/draft_authoring.py src/wf_api/draft_payloads.py src/wf_api/drafts.py src/wf_api/service.py tests/wf_api/test_drafts_service.py
git commit -m "refactor: separate draft semantic authoring"

Task 2: Remove The Superseded Partial State Projection Operation

Files:

  • Modify: src/wf_api/service.py

  • Modify: src/wf_api/surface.py

  • Modify: src/wf_transport_rpc_http/models.py

  • Modify: src/wf_transport_rpc_http/methods/drafts.py

  • Modify: src/wf_transport_rpc_http/client/drafts.py

  • Modify: src/wf_transport_rpc_http/__init__.py

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

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

  • Modify: src/wf_cli/commands/drafts.py

  • Modify: affected draft tests in tests/

  • Step 1: Prove no production caller remains

Run:

rg -n 'add_state_schema_from_output|add-state-from-output' src tests docs skills

Expected: only the operation implementation, adapters, tests, and docs refer to it; no independent production caller depends on it.

  • Step 2: Remove the operation end to end

Delete add_state_schema_from_output, its request/params DTOs, RPC method, client method, MCP tool, CLI command, exports, and dedicated tests. Do not add a compatibility shim. Keep bind_output_to_state as the complete semantic operation.

  • Step 3: Run surface import and help tests

Run:

uv run pytest tests/wf_cli/test_app.py tests/wf_transport_rpc_http/test_client.py tests/wf_mcp/server/test_config.py -q

Expected: PASS and no removed command/tool in enumerated surfaces.

  • Step 4: Commit
git add src tests
git commit -m "refactor: remove partial draft state projection"

Task 3: Add Atomic branch And handle Authoring Operations

Files:

  • Modify: src/wf_api/draft_authoring.py

  • Modify: src/wf_api/service.py

  • Modify: src/wf_api/surface.py

  • Modify: src/wf_transport_rpc_http/models.py

  • Modify: src/wf_transport_rpc_http/methods/drafts.py

  • Modify: src/wf_transport_rpc_http/client/drafts.py

  • Modify: src/wf_transport_rpc_http/__init__.py

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

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

  • Modify: src/wf_cli/commands/drafts.py

  • Test: tests/wf_api/test_drafts_service.py

  • Test: tests/wf_transport_rpc_http/test_app.py

  • Test: tests/wf_transport_rpc_http/test_client.py

  • Test: tests/wf_cli/test_remote_target.py

  • Test: tests/wf_mcp/server/test_config.py

  • Step 1: Write failing API tests

Cover atomic route updates and preservation:

result = await api.branch_draft(
    workspace_id="branching",
    revision=1,
    step_id="classify",
    routes={"ok": "next", "error": "tool_error"},
)
assert result["revision"] == 2
workspace = await api.get_draft_workspace(workspace_id="branching")
assert workspace["draft"]["routes"]["classify"] == {
    "ok": "next",
    "error": "tool_error",
    "retry": "retry_step",
}

Add a handle_draft test updating two source outcomes in one revision. Assert empty mappings, duplicate CLI values, unknown source steps, and unknown declared outcomes leave the workspace byte-for-byte unchanged.

  • Step 2: Implement semantic methods

Use protocol-neutral signatures. branch_draft takes keyword-only workspace_id: str, revision: int, step_id: str, and routes: dict[str, str]. handle_draft takes keyword-only workspace_id: str, revision: int, branches: Sequence[DraftOutcomeRef], and target: str. Both return dict[str, Any].

Define DraftOutcomeRef as a small frozen Pydantic model or dataclass with step_id and outcome. Validate request-local preconditions first, build one JSON Patch list, then call WorkflowDraftApi.patch_draft_workspace once.

  • Step 3: Add transport models and methods

RPC and MCP request models use structured branch records. Register:

workflow.draft_workspaces.branch
workflow.draft_workspaces.handle
wf.workflow.branch_draft
wf.workflow.handle_draft

Extend WorkflowDraftSurface and the RPC client mixin with the exact API signatures.

  • Step 4: Add CLI commands

Expose:

wf draft branch WORKSPACE --revision N --step STEP --route ok=next --route error=fail
wf draft handle WORKSPACE --revision N --to fail --branch lookup:error --branch transform:error

Parse route values with the existing strict KEY=VALUE utility. Parse branch values at the final colon, reject duplicates, and send structured records.

  • Step 5: Run vertical-slice tests
uv run pytest tests/wf_api/test_drafts_service.py tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py tests/wf_cli/test_remote_target.py tests/wf_mcp/server/test_config.py -q

Expected: PASS.

  • Step 6: Commit
git add src tests
git commit -m "feat: add semantic draft branch and handle"

Task 4: Make Capability-Step Routing Complete

Files:

  • Modify: src/wf_api/draft_authoring.py

  • Modify: src/wf_api/service.py

  • Modify: src/wf_api/surface.py

  • Modify: src/wf_transport_rpc_http/models.py

  • Modify: src/wf_transport_rpc_http/methods/drafts.py

  • Modify: src/wf_transport_rpc_http/client/drafts.py

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

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

  • Modify: src/wf_cli/commands/drafts.py

  • Test: affected API/RPC/MCP/CLI draft tests

  • Step 1: Write failing routing-policy tests

Cover three cases:

# One declared outcome named "done", no routes supplied.
assert added_routes == {"done": "__end__"}

# No outcome metadata, no routes supplied.
assert added_routes == {"ok": "__end__"}

# Multiple declared outcomes, incomplete explicit routes.
with pytest.raises(ValueError, match="missing routes.*error"):
    await api.add_step_from_capability(
        workspace_id="multi",
        revision=1,
        step_id="echo",
        capability_name="demo.echo",
        routes={"ok": "__end__"},
    )

Also assert complete multi-outcome routes succeed in one revision.

  • Step 2: Replace singular route parameters

Replace route_outcome and route_to with:

routes: dict[str, str] | None = None

Resolve declared capability outcomes before mutation. Infer the sole outcome regardless of name; use ok only when metadata supplies none. For multiple declared outcomes, require exact coverage and report declared_outcomes, missing_outcomes, and unknown_outcomes in the application error.

  • Step 3: Update all public adapters

RPC and MCP accept a route mapping. CLI replaces singular --outcome/--to with repeatable --route OUTCOME=TARGET. Update help to explain sole-outcome inference and multi-outcome completeness.

  • Step 4: Run focused tests
uv run pytest tests/wf_api/test_drafts_service.py tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py tests/wf_mcp/server/test_config.py -q

Expected: PASS.

  • Step 5: Commit
git add src tests
git commit -m "fix: require complete capability step routes"

Task 5: Compile A Stored Draft Workspace Without Mutation

Files:

  • Modify: src/wf_api/drafts.py

  • Modify: src/wf_api/service.py

  • Modify: src/wf_api/surface.py

  • Modify: src/wf_transport_rpc_http/models.py

  • Modify: src/wf_transport_rpc_http/methods/drafts.py

  • Modify: src/wf_transport_rpc_http/client/drafts.py

  • Modify: src/wf_transport_rpc_http/__init__.py

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

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

  • Modify: src/wf_cli/commands/drafts.py

  • Test: affected API/RPC/MCP/CLI draft tests

  • Step 1: Write failing no-mutation API tests

Capture the workspace before and after compilation:

before = await api.get_draft_workspace(workspace_id="compile_me")
result = await api.compile_draft_workspace(workspace_id="compile_me")
after = await api.get_draft_workspace(workspace_id="compile_me")

assert result["compiled_plan"]["name"] == "compile_me"
assert result["required_capabilities"]
assert after == before

Add an invalid-workspace test asserting structured diagnostics and no compiled_plan.

  • Step 2: Implement the read-only projection

Add:

async def compile_draft_workspace(self, *, workspace_id: str) -> dict[str, Any]:
    workspace = self._draft_store().get_workspace(workspace_id)
    validation = await self.validate_draft(draft=workspace.draft)
    if validation["status"] != "valid":
        return validation
    return await self.compile_draft(draft=workspace.draft)

Do not call validate_draft_workspace, because that operation refreshes stored status and diagnostics.

  • Step 3: Expose RPC and MCP operations

Register:

workflow.draft_workspaces.compile
wf.workflow.compile_draft_workspace

Return the application envelope containing compiled_plan and required_capabilities.

  • Step 4: Add the CLI projection

Expose wf draft compile WORKSPACE. On success print only result["compiled_plan"]. On invalid status, print the structured diagnostic envelope to stderr and exit nonzero. Do not add an output-file option.

  • Step 5: Run focused tests
uv run pytest tests/wf_api/test_drafts_service.py tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py tests/wf_mcp/workflow_surface/test_drafts.py -q

Expected: PASS.

  • Step 6: Commit
git add src tests
git commit -m "feat: compile stored draft workspaces"

Task 6: Documentation, Skills, And End-To-End Regression

Files:

  • Modify: docs/workflow_drafts.md

  • Modify: docs/wf_cli.md

  • Modify: docs/wf_authoring_control_flow.md

  • Modify: skills/wf-cli/SKILL.md

  • Modify: skills/wf-workflow/SKILL.md

  • Modify: skills/wf-workflow/references/draft-workspaces.md

  • Modify: skills/wf-workflow/references/workflow-lifecycle.md

  • Modify: docs/current_roadmap.md

  • Modify: docs/superpowers/specs/2026-06-27-draft-semantic-authoring-boundary.md

  • Test: tests/wf_cli/test_remote_target.py

  • Move after completion: docs/superpowers/plans/2026-06-27-draft-semantic-authoring-and-compile.md -> docs/historical/superpowers/plans/2026-06-27-draft-semantic-authoring-and-compile.md

  • Step 1: Add a two-step multi-outcome integration regression

Use the running RPC test fixture or local static server to:

  1. create a workspace from a capability;
  2. add a second capability declaring ok and error with both routes;
  3. validate without a follow-up set-route call;
  4. save the artifact and deployment;
  5. run it and assert two trace frames completed.

This test must fail against the old singular-route helper.

  • Step 2: Reorganize public guidance by operation level

Document semantic operations first, focused edits second, patch last. Explain that branch and handle mirror WorkflowBuilder but mutate WorkflowDraft. Document compile as read-only and show that it prints a raw plan without saving an artifact.

  • Step 3: Document extensibility without implementing extra step kinds

State that WorkflowDraftAuthoringApi is the home for future semantic helpers for interrupt, foreach, condition, join/end, and future core step kinds. Do not add commands for them in this slice.

  • Step 4: Update status documents

Mark the design implemented, record the completed roadmap item, update live links, and archive this plan.

  • Step 5: Run final verification
uv run pytest tests/wf_api/test_drafts_service.py tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py tests/wf_mcp/workflow_surface/test_drafts.py tests/wf_mcp/server/test_config.py -q
uv run ruff check
uv run ruff format --check
uv run basedpyright --level error
git diff --check

Expected: all tests pass, Ruff is clean, basedpyright reports zero errors, and there are no whitespace errors.

  • Step 6: Archive and commit
git mv docs/superpowers/plans/2026-06-27-draft-semantic-authoring-and-compile.md docs/historical/superpowers/plans/2026-06-27-draft-semantic-authoring-and-compile.md
git add docs skills tests
git commit -m "docs: record semantic draft authoring surface"