# Capability Step Update 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:** Add one atomic, presence-aware capability-step update across Python, JSON-RPC, MCP, and CLI, and let capability-step creation set the same metadata and canonical literal inputs directly. **Architecture:** Define a transport-safe `CapabilityStepUpdate` model in `wf_api`, then keep all semantic mutation in `WorkflowDraftAuthoringApi`. Extract the existing capability-aware input-binding preflight into one private implementation reused by set-input, update, and creation. RPC, MCP, and CLI are adapters that preserve omitted fields, explicit metadata nulls, and canonical binding order. **Tech Stack:** Python 3.14, Pydantic 2, Typer, FastAPI JSON-RPC, FastMCP, pytest, Ruff, basedpyright. ## Global Constraints - Never change an existing step's `use` capability. - Preserve routes, output bindings, and unrelated step fields. - Omitted update fields preserve stored values. - Explicit metadata `null` clears; explicit `input: null` is invalid. - Supplied `input` replaces the complete ordered canonical list; `[]` clears. - Reuse one capability-aware input preflight for set-input, update, and add. - Stale revision wins over semantic step, capability, path, and schema errors. - Metadata-only updates must not resolve the capability source. - Exact no-ops do not increment revision. - Input clearing does not delete previously projected workflow schemas. - Keep compatibility `input_map` for real callers, but reject simultaneous compatibility and canonical input forms. - Keep routes and output bindings under their existing focused operations. - Python baseline is 3.14. Add comments/docstrings around field-presence and schema-projection behavior that is not obvious. - Use scoped tests in each task and the complete focused matrix only in Task 5. --- ### Task 1: Presence-Aware Model And Canonical Authoring **Files:** - Create: `src/wf_api/draft_updates.py` - Modify: `src/wf_api/__init__.py` - Modify: `src/wf_api/draft_authoring.py` - Modify: `tests/wf_api/test_drafts_service.py` **Interfaces:** - Produces: `CapabilityStepUpdate(desc, retry, timeout_seconds, input)`. - Produces: `WorkflowDraftAuthoringApi.update_capability_step(*, workspace_id: str, revision: int, step_id: str, update: CapabilityStepUpdate)`. - Extends: `WorkflowDraftAuthoringApi.add_step_from_capability(..., desc=None, retry=None, timeout_seconds=None, input_bindings=None)`. - Preserves: `WorkflowDraftAuthoringApi.set_step_input_bindings(...)`. - [x] **Step 1: Write failing update-model tests** Add focused tests in `tests/wf_api/test_drafts_service.py`: ```python def test_capability_step_update_preserves_field_presence() -> None: update = CapabilityStepUpdate.model_validate( {"desc": None, "retry": 0, "input": []} ) assert update.model_fields_set == {"desc", "retry", "input"} assert update.desc is None assert update.retry == 0 assert update.input == [] @pytest.mark.parametrize( "payload", [ {}, {"input": None}, {"desc": ""}, {"retry": -1}, {"timeout_seconds": 0}, ], ) def test_capability_step_update_rejects_invalid_patch(payload: object) -> None: with pytest.raises(ValidationError): CapabilityStepUpdate.model_validate(payload) ``` - [x] **Step 2: Run the model tests red** Run: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` tests/wf_api/test_drafts_service.py ` -q -k "capability_step_update_preserves or capability_step_update_rejects" ` --basetemp=.pytest-capability-update-model-red ``` Expected: collection fails because `CapabilityStepUpdate` does not exist. - [x] **Step 3: Implement the update model** Create `src/wf_api/draft_updates.py`: ```python from __future__ import annotations from typing import Self from pydantic import BaseModel, ConfigDict, Field, model_validator from wf_core.models.steps import InputBinding class CapabilityStepUpdate(BaseModel): """Presence-aware patch for one existing capability-backed draft step.""" model_config = ConfigDict(extra="forbid") desc: str | None = Field(default=None, min_length=1) retry: int | None = Field(default=None, ge=0) timeout_seconds: int | None = Field(default=None, gt=0) input: list[InputBinding] | None = None @model_validator(mode="after") def validate_patch_shape(self) -> Self: if not self.model_fields_set: raise ValueError("capability step update requires at least one field") if "input" in self.model_fields_set and self.input is None: raise ValueError("capability step update input must be a list") return self ``` Export it from `src/wf_api/__init__.py`. Run the model tests green. - [x] **Step 4: Write failing semantic update tests** Add a helper that creates a capability-backed draft step containing: - `use`; - path and literal input bindings; - output bindings; - `desc`; - `retry`; - `timeout_seconds`; - routes. Add tests with field-level assertions: ```python @pytest.mark.asyncio async def test_update_capability_step_changes_metadata_and_inputs_atomically( tmp_path: Path, ) -> None: draft_api, _, authoring = _draft_api( FileWorkflowArtifactStore(tmp_path / "update_capability"), register_echo=True, ) draft = _echo_draft() draft["steps"]["echo"].update( { "desc": "Old description", "retry": 1, "timeout_seconds": 10, } ) await draft_api.create_draft_workspace(workspace_id="echo", draft=draft) result = await authoring.update_capability_step( workspace_id="echo", revision=1, step_id="echo", update=CapabilityStepUpdate.model_validate( { "desc": "New description", "retry": 0, "timeout_seconds": None, "input": [ {"path": "input.text", "target": "text"}, ], } ), ) inspected = await draft_api.get_draft_workspace( workspace_id="echo", include_draft=True, ) step = inspected["draft"]["steps"]["echo"] assert result["revision"] == 2 assert step["use"] == "demo.personal.echo_tool" assert step["desc"] == "New description" assert step["retry"] == 0 assert "timeout_seconds" not in step assert step["input"] == [{"path": "input.text", "target": "text"}] assert step["output"] == draft["steps"]["echo"]["output"] assert inspected["draft"]["routes"]["echo"] == {"ok": "__end__"} ``` Add separate tests for: - omitted fields preserved; - each metadata field set and cleared; - exact no-op keeps revision; - `input=[]` clears bindings but preserves projected schemas; - metadata-only update succeeds when capability lookup is monkeypatched to fail; - missing step and non-`DraftUseStep` rejection; - stale revision wins over missing step, wrong kind, and unavailable capability; - malformed input leaves the complete inspected workspace unchanged; - path/literal input replacement projects schemas and preserves order; - compile/run succeeds after one combined metadata/input update. - [x] **Step 5: Run semantic tests red** Run: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` tests/wf_api/test_drafts_service.py ` -q -k "update_capability_step" ` --basetemp=.pytest-capability-update-authoring-red ``` Expected: failures because the authoring method does not exist. - [x] **Step 6: Extract one shared input-binding preflight** In `src/wf_api/draft_authoring.py`, add a private result model: ```python @dataclass(frozen=True) class _ProjectedStepInputBindings: payload: list[dict[str, Any]] input_schema: dict[str, Any] state_schema: dict[str, Any] ``` Extract the current semantic body of `set_step_input_bindings` into a private method: ```python def _project_step_input_bindings( self, *, workspace: WorkflowDraftWorkspace, capability_name: str, bindings: Sequence[InputBinding], ) -> _ProjectedStepInputBindings: """Validate canonical inputs and project missing workflow source schemas.""" ``` This method must: 1. resolve the capability; 2. reject overlapping local targets; 3. require every target in the capability input schema; 4. validate literal values, including root-object behavior; 5. preserve `context.*` without schema projection; 6. project missing `input.*` and `state.*` source schemas; 7. return canonical binding payload and projected schemas. Rewrite `set_step_input_bindings` to call this method, preserving its no-op and patch behavior. Run all existing `set_step_input_bindings` tests before adding the update method: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` tests/wf_api/test_drafts_service.py ` -q -k "step_input_bindings" ` --basetemp=.pytest-capability-update-shared-preflight ``` Expected: PASS. - [x] **Step 7: Implement atomic capability-step update** Implement: ```python async def update_capability_step( self, *, workspace_id: str, revision: int, step_id: str, update: CapabilityStepUpdate, ) -> dict[str, Any]: """Patch capability metadata and optional canonical inputs atomically.""" ``` Required implementation shape: ```python checked = self._workspace_if_revision_matches( workspace_id=workspace_id, revision=revision, ) if isinstance(checked, dict): return checked workspace = checked step = draft_step(workspace.draft, step_id) if step.get("kind") != "use": raise ValueError(f"step {step_id!r} is not capability-backed") current = DraftUseStep.model_validate(step) changes: dict[str, object] = {} for field in ("desc", "retry", "timeout_seconds"): if field in update.model_fields_set: changes[field] = getattr(update, field) projected = None if "input" in update.model_fields_set: assert update.input is not None projected = self._project_step_input_bindings( workspace=workspace, capability_name=current.use, bindings=update.input, ) changes["input"] = update.input changed = current.model_copy(update=changes) step_payload = changed.model_dump( mode="json", by_alias=True, exclude_none=True, ) ``` Do not use `model_copy(update=...)` with unvalidated external values; all values here come from `CapabilityStepUpdate`. Build one patch for changed schemas plus replacement of `/steps/`. If the step payload and schemas are unchanged, return `summarize_draft_workspace(workspace)`. - [x] **Step 8: Write failing creation-parity tests** Add tests proving: ```python result = await authoring.add_step_from_capability( workspace_id="report", revision=1, step_id="publish", capability_name="demo.personal.structured_report", routes={"ok": "__end__"}, desc="Publish report", retry=2, timeout_seconds=30, input_bindings=[ InputPathBinding( path=GraphSourcePath.state("report", "title"), target=LocalPath.of("request", "title"), ), InputValueBinding( target=LocalPath.of("request", "format"), value="markdown", ), ], ) ``` Assert metadata, ordered canonical bindings, and projected schemas. Add tests rejecting `input_map` and `input_bindings` whenever both arguments are supplied, including an explicit empty compatibility map, and proving existing map-only callers retain behavior. - [x] **Step 9: Extend creation through the shared preflight** Extend the method signature: ```python async def add_step_from_capability( ..., input_map: dict[str, str] | None = None, input_bindings: Sequence[InputBinding] | None = None, bind_outputs: dict[str, str] | None = None, desc: str | None = None, retry: int | None = None, timeout_seconds: int | None = None, ) -> dict[str, Any]: ``` If both canonical bindings and a compatibility map are supplied, even when either collection is explicitly empty, raise: ```text input_map and input_bindings are mutually exclusive ``` Lower compatibility `input_map` with `input_bindings_payload(input_map, {})` and validate the resulting typed list, or accept `input_bindings` directly. Use `_project_step_input_bindings` for both. Persist metadata only when not `None`; `retry=0` must survive. - [x] **Step 10: Verify and commit Task 1** Run: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` tests/wf_api/test_drafts_service.py -q ` --basetemp=.pytest-capability-update-task1 .venv\Scripts\ruff.exe check ` src/wf_api/draft_updates.py ` src/wf_api/draft_authoring.py ` tests/wf_api/test_drafts_service.py .venv\Scripts\basedpyright.exe --level error ` src/wf_api/draft_updates.py ` src/wf_api/draft_authoring.py ``` Then: ```bash git add src/wf_api/__init__.py src/wf_api/draft_updates.py \ src/wf_api/draft_authoring.py tests/wf_api/test_drafts_service.py git commit -m "feat: update capability-backed draft steps" ``` --- ### Task 2: Public Interface And JSON-RPC **Files:** - Modify: `src/wf_api/surface.py` - Modify: `src/wf_api/service.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: `tests/wf_transport_rpc_http/test_app.py` - Modify: `tests/wf_transport_rpc_http/test_client.py` **Interfaces:** - Consumes: Task 1's `CapabilityStepUpdate`, `update_capability_step(...)`, and extended `add_step_from_capability(...)`. - Produces: `workflow.draft_workspaces.update_capability_step`. - Extends the existing add-capability RPC with metadata and canonical `input_bindings`. - [x] **Step 1: Write failing RPC model tests** Add tests for: ```python params = UpdateCapabilityStepParams.model_validate( { "workspace_id": "report", "revision": 4, "step_id": "publish", "update": {"desc": None, "retry": 0}, } ) assert params.update.model_fields_set == {"desc", "retry"} assert params.update.desc is None assert params.update.retry == 0 ``` Add malformed cases for empty update, `input:null`, negative retry, zero timeout, and unknown fields. Extend `AddStepFromCapabilityParams` tests for metadata, canonical path/value order, and simultaneous `input_map` plus `input_bindings`. - [x] **Step 2: Run RPC model tests red** Run the focused new tests. Expected: import/model failures. - [x] **Step 3: Add RPC models** Add: ```python class UpdateCapabilityStepParams(RpcParamsModel): workspace_id: str = Field(min_length=1) revision: int = Field(ge=1) step_id: str = Field(min_length=1) update: CapabilityStepUpdate ``` Extend `AddStepFromCapabilityParams`: ```python input_map: dict[str, str] | None = None input_bindings: list[InputBinding] | None = None desc: str | None = Field(default=None, min_length=1) retry: int | None = Field(default=None, ge=0) timeout_seconds: int | None = Field(default=None, gt=0) ``` Add a model validator rejecting both input forms when both were supplied. - [x] **Step 4: Write failing endpoint and client tests** Add a real ASGI test that creates a capability step, updates metadata and a literal input through: ```text workflow.draft_workspaces.update_capability_step ``` Inspect the draft and assert preservation of `use`, routes, and outputs. Add a client serialization test that passes: ```python CapabilityStepUpdate.model_validate({"desc": None, "retry": 0}) ``` and asserts the emitted nested object is exactly: ```python {"desc": None, "retry": 0} ``` No default `timeout_seconds` or `input` keys may appear. Extend add-capability client tests for canonical input order and metadata. - [x] **Step 5: Implement public and RPC adapters** Add the update method to `WorkflowDraftSurface` and `WorkflowApi`, delegating to `draft_authoring`. Register the RPC method and client. The client must serialize: ```python update.model_dump(mode="json", exclude_unset=True) ``` Extend every add-capability seam with the Task 1 fields. Compatibility map-only calls remain valid. - [x] **Step 6: Verify and commit Task 2** Run: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` tests/wf_transport_rpc_http/test_app.py ` tests/wf_transport_rpc_http/test_client.py ` -q --basetemp=.pytest-capability-update-task2 .venv\Scripts\ruff.exe check src/wf_api src/wf_transport_rpc_http ` tests/wf_transport_rpc_http .venv\Scripts\basedpyright.exe --level error ``` Commit: ```bash git add src/wf_api/surface.py src/wf_api/service.py \ src/wf_transport_rpc_http tests/wf_transport_rpc_http git commit -m "feat: expose capability step updates over rpc" ``` --- ### Task 3: MCP Update Tool And Creation Parity **Files:** - Modify: `src/wf_mcp/workflow_surface/models.py` - Modify: `src/wf_mcp/workflow_surface/tools.py` - Modify: `src/wf_mcp/proxy/runtime.py` - Modify: `tests/wf_mcp/workflow_surface/test_drafts.py` - Modify: `tests/wf_mcp/server/test_tools.py` - Modify: `tests/wf_mcp/server/test_config.py` **Interfaces:** - Consumes: Task 2's public update method and Task 1's model. - Produces: `wf.workflow.update_capability_step`. - Extends: `wf.workflow.add_step_from_capability`. - [x] **Step 1: Write failing MCP request tests** Add: ```python request = UpdateCapabilityStepRequest.model_validate( { "workspace_id": "report", "revision": 4, "step_id": "publish", "update": { "desc": None, "input": [ {"value": "markdown", "target": "request.format"}, ], }, } ) assert request.update.model_fields_set == {"desc", "input"} assert isinstance(request.update.input[0], InputValueBinding) ``` Add malformed update cases and add-capability request parity tests. - [x] **Step 2: Write failing discovery and real invocation tests** Require the tool in normal and search-mode inventories. Call it through an in-memory FastMCP client and assert: - one delegation; - typed `CapabilityStepUpdate`; - exact `model_fields_set`; - exact canonical binding order. Extend the add-capability invocation test with metadata and a literal binding. - [x] **Step 3: Implement MCP request and tools** Add: ```python class UpdateCapabilityStepRequest(BaseModel): workspace_id: WorkspaceId revision: int = Field(ge=1) step_id: NonEmptyString update: CapabilityStepUpdate ``` Register: ```python @server.tool( name="wf.workflow.update_capability_step", title="Update Capability Step", description=( "Update capability-step metadata and optionally replace its complete " "canonical input bindings. Preserves use, routes, and outputs." ), ) async def update_capability_step( request: UpdateCapabilityStepRequest, ) -> DraftWorkspaceResult: return DraftWorkspaceResult.model_validate( await handlers.update_capability_step( workspace_id=request.workspace_id, revision=request.revision, step_id=request.step_id, update=request.update, ) ) ``` Add the name to `_SEARCH_ALWAYS_VISIBLE_TOOL_NAMES`. Extend `AddStepFromCapabilityRequest` and its tool delegation with the creation-parity fields. - [x] **Step 4: Verify and commit Task 3** Run: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` tests/wf_mcp/workflow_surface/test_drafts.py ` tests/wf_mcp/server/test_tools.py ` tests/wf_mcp/server/test_config.py ` -q --basetemp=.pytest-capability-update-task3 .venv\Scripts\ruff.exe check src/wf_mcp tests/wf_mcp .venv\Scripts\basedpyright.exe --level error ``` Commit: ```bash git add src/wf_mcp tests/wf_mcp git commit -m "feat: expose capability step updates to mcp" ``` --- ### Task 4: Add And Update CLI **Files:** - Create: `src/wf_cli/commands/draft_update.py` - Modify: `src/wf_cli/commands/draft_add.py` - Modify: `src/wf_cli/commands/draft_options.py` - Modify: `src/wf_cli/commands/drafts.py` - Modify: `tests/wf_cli/test_app.py` - Modify: `tests/wf_cli/test_remote_target.py` **Interfaces:** - Consumes: Task 2's local/remote update and extended add methods. - Produces: `wf draft update capability`. - Extends: `wf draft add capability`. - [x] **Step 1: Write failing parser tests** Refactor the private input-shaped path parser so the option name and target audience are parameters: ```python def _parse_input_path_binding_flags( values: list[str] | None, *, option_name: str, target_label: str, ) -> list[InputPathBinding]: ``` Keep `parse_step_input_binding_flags` behavior unchanged. Add: ```python def parse_capability_input_binding_flags( values: list[str] | None, ) -> list[InputPathBinding]: return _parse_input_path_binding_flags( values, option_name="--input", target_label="node-local", ) ``` Reuse `parse_step_input_value_flags` and `parse_step_input_bindings_file`. Write tests for `--input`-specific diagnostics and canonical order. - [x] **Step 2: Write failing update command tests** Add local CLI tests for: ```bash wf draft update capability report --revision 4 --step publish \ --description "Publish report" \ --retry 0 \ --clear-timeout \ --input state.report.title=request.title \ --value request.format='"markdown"' ``` Assert the fake handler receives a `CapabilityStepUpdate` whose `model_fields_set` is exactly: ```python {"desc", "retry", "timeout_seconds", "input"} ``` and whose input bindings preserve path-then-literal order. Add tests for every set/clear conflict, bindings-file conflict, clear-input conflict, empty update, and validation before `load_cli_context`. - [x] **Step 3: Implement the update command group** Create `draft_update.py` with a Typer group and `capability` command. Build a plain `payload` dictionary only from selected flags: ```python payload: dict[str, object] = {} if description is not None: payload["desc"] = description elif clear_description: payload["desc"] = None if retry is not None: payload["retry"] = retry elif clear_retry: payload["retry"] = None if timeout_seconds is not None: payload["timeout_seconds"] = timeout_seconds elif clear_timeout: payload["timeout_seconds"] = None if input_mode_selected: payload["input"] = bindings update = CapabilityStepUpdate.model_validate(payload) ``` Parse all exclusivity and validation errors before loading context. Register: ```python app.add_typer(draft_update.app, name="update") ``` in `drafts.py`. - [x] **Step 4: Write failing add-command parity tests** Test `wf draft add capability` with metadata, `--input`, `--value`, and `--bindings-file`. Pin: - canonical path/value order; - `retry=0`; - bindings-file exact interleaving; - file/convenience exclusivity before context; - existing path-only invocation unchanged. - [x] **Step 5: Extend add capability** Add the approved flags and call canonical `input_bindings`. Do not pass both the compatibility map and canonical list. The CLI should use canonical bindings for every new invocation; `input_map` remains only for non-CLI compatibility callers. - [x] **Step 6: Add remote parity tests** Use the real ASGI RPC target to assert exact methods and payloads: ```text workflow.draft_workspaces.update_capability_step workflow.draft_workspaces.add_step_from_capability ``` For update, assert omitted metadata keys do not appear and explicit clears do. For add, assert ordered path/value input bindings and metadata. - [x] **Step 7: Verify and commit Task 4** Run: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` tests/wf_cli/test_app.py ` tests/wf_cli/test_remote_target.py ` -q --basetemp=.pytest-capability-update-task4 .venv\Scripts\ruff.exe check src/wf_cli tests/wf_cli .venv\Scripts\basedpyright.exe --level error ``` Commit: ```bash git add src/wf_cli tests/wf_cli git commit -m "feat: add capability step update cli" ``` --- ### Task 5: Documentation, Verification, And Review **Files:** - Modify: `ISSUES.md` - Modify: `docs/wf_cli.md` - Modify: `docs/workflow_drafts.md` - Modify: `docs/workflow_capabilities.md` - Modify: `docs/wf_mcp_operator_manual.md` - Modify: `skills/wf-cli/SKILL.md` - Modify: `skills/wf-workflow/references/draft-workspaces.md` - Modify: `skills/wf-workflow/references/workflow-lifecycle.md` - Modify: `docs/current_roadmap.md` - Move: `docs/superpowers/plans/2026-07-26-capability-step-update.md` to `docs/historical/superpowers/plans/2026-07-26-capability-step-update.md` **Interfaces:** - Consumes: verified Tasks 1-4. - Produces: accurate current docs, closed issue state, archived checked plan, and final review evidence. - [x] **Step 1: Update issue and roadmap state** Mark the focused capability-step update issue complete. State that: - creation accepts metadata and canonical literal inputs; - update preserves `use`, routes, and outputs; - update can atomically replace canonical input bindings; - changing capability remains remove/add; - TypeScript parity remains open. Add a completed roadmap entry linked to the historical plan. - [x] **Step 2: Update user and agent docs** Document: ```bash wf draft add capability report --revision 3 --step publish \ --capability local.report.publish \ --description "Publish report" \ --retry 2 \ --timeout-seconds 30 \ --input state.report.title=request.title \ --value request.format='"markdown"' \ --route ok=__end__ wf draft update capability report --revision 4 --step publish \ --clear-description \ --retry 0 \ --clear-timeout ``` Explain omission versus clearing, complete input replacement, bindings-file interleaving, and separate route/output operations. Add JSON-RPC and MCP operation names to live inventories. - [x] **Step 3: Archive the checked plan** Mark every checkbox complete, move the plan to the historical path, and update all live links: ```powershell rg -n '2026-07-26-capability-step-update' docs skills README.md ``` - [x] **Step 4: Run the full focused matrix** Run: ```powershell .venv\Scripts\python.exe -m pytest -n 0 ` 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_mcp/workflow_surface/test_drafts.py ` tests/wf_mcp/server/test_tools.py ` tests/wf_mcp/server/test_config.py ` tests/wf_cli/test_app.py ` tests/wf_cli/test_remote_target.py ` -q --basetemp=.pytest-capability-update-final ``` Expected: PASS with only already-known dependency deprecation warnings. - [x] **Step 5: Run static verification** Run: ```powershell .venv\Scripts\ruff.exe check .venv\Scripts\ruff.exe format --check .venv\Scripts\basedpyright.exe --level error git diff --check ``` Expected: all clean. - [x] **Step 6: Run independent two-axis review** Review from commit `05afc2e1` through the current worktree against: ```text docs/superpowers/specs/2026-07-26-capability-step-update-design.md ``` Require findings first with severity and file/line references. The spec reviewer must inspect: - omission versus explicit null; - explicit `input:null` rejection; - stale-revision precedence; - metadata-only operation without capability resolution; - no-op revision behavior; - preservation of `use`, outputs, and routes; - shared input preflight rather than duplicated semantics; - add/update canonical input parity; - RPC `exclude_unset=True`; - CLI pre-context exclusivity; - MCP discovery and real invocation; - docs and issue truthfulness. Fix every Critical and Important finding and rerun affected checks. - [x] **Step 7: Commit documentation and review fixes** Commit documentation: ```bash git add ISSUES.md docs skills git commit -m "docs: complete capability step updates" ``` Commit production/test review fixes separately after verification. Finish: ```powershell git status --short --branch git log --oneline -10 ``` Expected: clean worktree and task-level commits.