docs: archive completed superpowers plans
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
# Draft Output Binding Docs 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:** Clarify the two different `output` binding shapes in workflow drafts so MCP/LLM clients stop applying step-level `source`/`target` bindings to top-level workflow output projection.
|
||||
|
||||
**Architecture:** This is docs-only for now. The core model is internally coherent: step-level `output` uses `OutputBinding` (`source` local -> `target` state), while top-level workflow `output` uses input-binding shape (`path` graph -> `target` local output payload). Update the main draft docs, runbook, and schema-facing descriptions to teach this explicitly without changing runtime behavior.
|
||||
|
||||
**Tech Stack:** Markdown docs, Pydantic field descriptions, pytest schema/docs tests, ruff, basedpyright.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
Do:
|
||||
|
||||
- Add a clear “Two Outputs, Different Shapes” docs section.
|
||||
- Show exact JSON for both step-level output and top-level workflow output.
|
||||
- Explain the legacy fallback: empty top-level `output` projects same-name top-level state fields.
|
||||
- Update MCP model field descriptions so schema viewers see “uses `path`, not `source`” for top-level output.
|
||||
- Add docs/test assertions that this guidance is exported.
|
||||
|
||||
Do not:
|
||||
|
||||
- Rename fields to `writes` / `returns`.
|
||||
- Change validation behavior.
|
||||
- Remove legacy same-name output fallback.
|
||||
- Add automatic MCP content block extraction.
|
||||
|
||||
## Files
|
||||
|
||||
- Modify: `docs/workflow_drafts.md`
|
||||
- Add the primary explanation and examples.
|
||||
- Modify: `docs/wf_mcp_end_to_end_runbook.md`
|
||||
- Add a short warning in the draft patching section.
|
||||
- Modify: `docs/workflow_capabilities.md`
|
||||
- Mention that `next_actions.patch_examples` may include top-level output projection examples.
|
||||
- Modify: `src/wf_artifacts/drafts/models.py`
|
||||
- Improve `WorkflowDraft.output` field description.
|
||||
- Modify: `src/wf_core/models/workflow.py`
|
||||
- Improve `Workflow.output` field description.
|
||||
- Modify: `tests/wf_mcp/server/test_docs.py`
|
||||
- Assert exported docs include the new guidance.
|
||||
- Modify if needed: `tests/wf_mcp/server/test_config.py`
|
||||
- Assert schema descriptions include “path, not source” if exposed in tool schema.
|
||||
|
||||
## Task 1: Document The Two Output Shapes
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `docs/workflow_drafts.md`
|
||||
|
||||
- [ ] **Step 1: Add docs section**
|
||||
|
||||
After the “Important details” list or before “Explicit Outputs And Error Outcomes”, add:
|
||||
|
||||
```markdown
|
||||
## Two Outputs, Different Shapes
|
||||
|
||||
Drafts have two fields named `output`, but they do different jobs.
|
||||
|
||||
### Step-Level `steps.<id>.output`
|
||||
|
||||
Step output writes a node's local return payload into workflow state. It uses
|
||||
`source` / `target`:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": { "root": "local", "parts": ["text"] },
|
||||
"target": { "root": "state", "parts": ["result_text"] }
|
||||
}
|
||||
```
|
||||
|
||||
Read this as:
|
||||
|
||||
```text
|
||||
node output.text -> state.result_text
|
||||
```
|
||||
|
||||
### Top-Level `output`
|
||||
|
||||
Top-level workflow output projects graph values into the final public workflow
|
||||
output payload. It uses input-binding shape: `path` / `target`, not
|
||||
`source` / `target`.
|
||||
|
||||
```json
|
||||
{
|
||||
"path": { "root": "state", "parts": ["result_text"] },
|
||||
"target": { "root": "local", "parts": ["result_text"] }
|
||||
}
|
||||
```
|
||||
|
||||
Read this as:
|
||||
|
||||
```text
|
||||
state.result_text -> workflow output.result_text
|
||||
```
|
||||
|
||||
If top-level `output` is empty, the runtime keeps the legacy same-name fallback:
|
||||
for every field in `output_schema`, it copies the top-level state field with the
|
||||
same name when present. That fallback is convenient, but explicit output
|
||||
projection is clearer for new workflows.
|
||||
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run grep check**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
rg -n "Two Outputs, Different Shapes|path.*not.*source|state.result_text -> workflow output.result_text" docs/workflow_drafts.md
|
||||
```
|
||||
|
||||
Expected: all terms appear.
|
||||
|
||||
## Task 2: Update Runbook Warning And Example
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `docs/wf_mcp_end_to_end_runbook.md`
|
||||
|
||||
- [ ] **Step 1: Add warning near draft patching section**
|
||||
|
||||
Near “Patch Or Validate The Workspace”, add:
|
||||
|
||||
```markdown
|
||||
When patching output bindings, keep the two levels separate:
|
||||
|
||||
- Step-level `steps.<id>.output` uses `source` local -> `target` state.
|
||||
- Top-level `output` uses `path` graph -> `target` local output payload.
|
||||
|
||||
For explicit final output projection from state, use:
|
||||
|
||||
```json
|
||||
{
|
||||
"path": { "root": "state", "parts": ["result_text"] },
|
||||
"target": { "root": "local", "parts": ["result_text"] }
|
||||
}
|
||||
```
|
||||
|
||||
Do not use `source` at top level. `source` belongs to step output bindings.
|
||||
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run grep check**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
rg -n "Do not use `source` at top level|steps.<id>.output|result_text" docs/wf_mcp_end_to_end_runbook.md
|
||||
```
|
||||
|
||||
Expected: all terms appear.
|
||||
|
||||
## Task 3: Update Field Descriptions
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/wf_artifacts/drafts/models.py`
|
||||
- Modify: `src/wf_core/models/workflow.py`
|
||||
|
||||
- [ ] **Step 1: Update `WorkflowDraft.output` field description**
|
||||
|
||||
Change:
|
||||
|
||||
```python
|
||||
output: list[InputBinding] = Field(default_factory=list)
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```python
|
||||
output: list[InputBinding] = Field(
|
||||
default_factory=list,
|
||||
description=(
|
||||
"Top-level workflow output projection. Uses input-binding shape: "
|
||||
"`path` reads from input/state/context and `target` writes to the "
|
||||
"local public output payload. Do not use step output `source` here."
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update `Workflow.output` field description**
|
||||
|
||||
In `src/wf_core/models/workflow.py`, extend the `output` description to include:
|
||||
|
||||
```python
|
||||
"Use `path`, not `source`; `source` belongs to step-level node output bindings."
|
||||
```
|
||||
|
||||
Keep the existing legacy fallback explanation.
|
||||
|
||||
- [ ] **Step 3: Run focused schema/type checks**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run basedpyright --level error src/wf_artifacts/drafts/models.py src/wf_core/models/workflow.py
|
||||
uv run ruff check src/wf_artifacts/drafts/models.py src/wf_core/models/workflow.py
|
||||
uv run ruff format --check src/wf_artifacts/drafts/models.py src/wf_core/models/workflow.py
|
||||
```
|
||||
|
||||
Expected: pass.
|
||||
|
||||
## Task 4: Add Exported Docs Test
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `tests/wf_mcp/server/test_docs.py`
|
||||
|
||||
- [ ] **Step 1: Add docs resource assertion**
|
||||
|
||||
In the docs resource test that reads workflow authoring/draft docs, assert:
|
||||
|
||||
```python
|
||||
assert "Two Outputs, Different Shapes" in text
|
||||
assert "Do not use step output `source` here" in text or "Do not use `source` at top level" in text
|
||||
```
|
||||
|
||||
Use the existing variable names in the file. Do not assert whole payload dict equality.
|
||||
|
||||
- [ ] **Step 2: Run focused docs test**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_mcp/server/test_docs.py -q
|
||||
```
|
||||
|
||||
Expected: pass.
|
||||
|
||||
## Task 5: Optional Schema Description Test
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify if needed: `tests/wf_mcp/server/test_config.py`
|
||||
|
||||
- [ ] **Step 1: Inspect whether draft output field description is exposed**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_mcp/server/test_config.py -q
|
||||
```
|
||||
|
||||
If this test already inspects `create_draft_workspace` request schemas, add:
|
||||
|
||||
```python
|
||||
output_description = minimal_request["properties"]["output"]["description"]
|
||||
assert "path" in output_description
|
||||
assert "source" in output_description
|
||||
```
|
||||
|
||||
If the schema nests the description differently, skip this test change and rely
|
||||
on `test_docs.py`.
|
||||
|
||||
## Task 6: Final Verification
|
||||
|
||||
**Files:**
|
||||
|
||||
- All touched docs and Python files.
|
||||
|
||||
- [ ] **Step 1: Run focused tests**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run pytest tests/wf_mcp/server/test_docs.py tests/wf_mcp/server/test_config.py -q
|
||||
```
|
||||
|
||||
Expected: pass.
|
||||
|
||||
- [ ] **Step 2: Run touched-file lint/type checks**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
uv run ruff check src/wf_artifacts/drafts/models.py src/wf_core/models/workflow.py tests/wf_mcp/server/test_docs.py tests/wf_mcp/server/test_config.py
|
||||
uv run ruff format --check src/wf_artifacts/drafts/models.py src/wf_core/models/workflow.py tests/wf_mcp/server/test_docs.py tests/wf_mcp/server/test_config.py
|
||||
uv run basedpyright --level error src/wf_artifacts/drafts/models.py src/wf_core/models/workflow.py tests/wf_mcp/server/test_docs.py tests/wf_mcp/server/test_config.py
|
||||
```
|
||||
|
||||
Expected: pass.
|
||||
|
||||
- [ ] **Step 3: Optional full suite**
|
||||
|
||||
Run when time allows:
|
||||
|
||||
```powershell
|
||||
uv run pytest -q
|
||||
```
|
||||
|
||||
Expected current baseline: full suite passes with the existing skip/xfail count.
|
||||
|
||||
## Notes For Opencode
|
||||
|
||||
- This is docs/description work only.
|
||||
- Do not rename model fields.
|
||||
- Do not remove fallback same-name projection.
|
||||
- Do not auto-extract MCP content blocks.
|
||||
- The exact mental model to teach is:
|
||||
|
||||
```text
|
||||
steps.call.output: local node output -> workflow state
|
||||
workflow output: input/state/context graph path -> public output payload
|
||||
```
|
||||
Reference in New Issue
Block a user