docs: complete atomic step output bindings

This commit is contained in:
lda
2026-07-23 05:21:09 +07:00 Verified
parent ed0c42466e
commit 9f427c7e61
8 changed files with 111 additions and 63 deletions
+3 -6
View File
@@ -20,12 +20,9 @@
- [x] Focused draft authoring can add or replace literal node-input bindings - [x] Focused draft authoring can add or replace literal node-input bindings
comparable to `WorkflowBuilder.use(input=[{"target": ..., "value": ...}])` comparable to `WorkflowBuilder.use(input=[{"target": ..., "value": ...}])`
through canonical API, RPC, MCP, and CLI surfaces. through canonical API, RPC, MCP, and CLI surfaces.
- [ ] Focused step input/output maps collapse valid canonical fan-out bindings. - [ ] Compatibility step input/output maps can still collapse valid canonical
A source-to-target dictionary cannot represent one graph source feeding two fan-out bindings. Canonical input and output replacement preserve ordered
local inputs, or one local output feeding two state targets; a later merge can fan-out, but later compatibility-map merges remain inherently lossy.
therefore rewrite a valid binding list into a lossy map. Canonical step-input
replacement now preserves fan-out, but compatibility map readers/writers and
focused step-output maps remain lossy.
- [ ] Focused workflow-output authoring cannot add or update literal output - [ ] Focused workflow-output authoring cannot add or update literal output
bindings even though `WorkflowDraft.output` accepts canonical value bindings. bindings even though `WorkflowDraft.output` accepts canonical value bindings.
- [ ] Workflow output schema projection skips nested sources such as - [ ] Workflow output schema projection skips nested sources such as
+5
View File
@@ -810,6 +810,11 @@ stable.
projection, local/remote CLI modes, JSON-RPC, and MCP. Compatibility map projection, local/remote CLI modes, JSON-RPC, and MCP. Compatibility map
merge remains available but intentionally lossy. Implementation plan: merge remains available but intentionally lossy. Implementation plan:
[`atomic step input bindings`](historical/superpowers/plans/2026-07-22-atomic-step-input-bindings.md). [`atomic step input bindings`](historical/superpowers/plans/2026-07-22-atomic-step-input-bindings.md).
- Completed: capability-aware canonical step-output replacement now preserves
ordered repeated-source fan-out, projects missing state schemas atomically,
and is available through Python, JSON-RPC, MCP, and local/remote CLI modes.
Compatibility map merges remain available but inherently lossy. Implementation
plan: [`atomic step output bindings`](historical/superpowers/plans/2026-07-23-atomic-step-output-bindings.md).
Agent evaluation cohort status and policy: Agent evaluation cohort status and policy:
@@ -49,7 +49,7 @@
- Preserves: `set_step_output_map(..., merge=...)` unchanged as a compatibility operation. - Preserves: `set_step_output_map(..., merge=...)` unchanged as a compatibility operation.
- [ ] **Step 1: Write failing canonical replacement and fan-out tests** - [x] **Step 1: Write failing canonical replacement and fan-out tests**
Add tests alongside the canonical input-binding tests. Use an existing test Add tests alongside the canonical input-binding tests. Use an existing test
capability whose output schema contains a nested object, or register one with capability whose output schema contains a nested object, or register one with
@@ -102,7 +102,7 @@
] ]
``` ```
- [ ] **Step 2: Write failing schema projection tests** - [x] **Step 2: Write failing schema projection tests**
Cover nested source-to-target projection, whole-payload `.` projection, Cover nested source-to-target projection, whole-payload `.` projection,
exact-equivalent existing target acceptance, and incompatible existing target exact-equivalent existing target acceptance, and incompatible existing target
@@ -132,7 +132,7 @@
Verify the complete capability output object appears below Verify the complete capability output object appears below
`state_schema.properties.raw_result`. `state_schema.properties.raw_result`.
- [ ] **Step 3: Write failing semantic-error and revision tests** - [x] **Step 3: Write failing semantic-error and revision tests**
Add cases for: Add cases for:
@@ -157,7 +157,7 @@
await api.set_step_output_bindings(...) await api.set_step_output_bindings(...)
``` ```
- [ ] **Step 4: Run focused API tests and confirm RED** - [x] **Step 4: Run focused API tests and confirm RED**
Run: Run:
@@ -168,7 +168,7 @@
Expected: failures because `WorkflowApi.set_step_output_bindings` does not Expected: failures because `WorkflowApi.set_step_output_bindings` does not
exist. exist.
- [ ] **Step 5: Add output overlap and patch helpers** - [x] **Step 5: Add output overlap and patch helpers**
In `src/wf_api/draft_authoring.py`, add focused helpers beside the input In `src/wf_api/draft_authoring.py`, add focused helpers beside the input
equivalents: equivalents:
@@ -218,7 +218,7 @@
ancestry checks. Keep this comment at the helper call because the type seam ancestry checks. Keep this comment at the helper call because the type seam
is otherwise non-obvious. is otherwise non-obvious.
- [ ] **Step 6: Implement canonical output replacement** - [x] **Step 6: Implement canonical output replacement**
Add `WorkflowDraftAuthoringApi.set_step_output_bindings`: Add `WorkflowDraftAuthoringApi.set_step_output_bindings`:
@@ -308,13 +308,13 @@
target, and source so incompatible-schema diagnostics satisfy the public target, and source so incompatible-schema diagnostics satisfy the public
error contract. error contract.
- [ ] **Step 7: Expose the operation through the API protocol and service** - [x] **Step 7: Expose the operation through the API protocol and service**
Add the same `Sequence[OutputBinding]` signature to `WorkflowApiSurface` and Add the same `Sequence[OutputBinding]` signature to `WorkflowApiSurface` and
delegate from `WorkflowApi` to `self.draft_authoring` exactly as the canonical delegate from `WorkflowApi` to `self.draft_authoring` exactly as the canonical
input operation does. input operation does.
- [ ] **Step 8: Add compile-and-run fan-out coverage** - [x] **Step 8: Add compile-and-run fan-out coverage**
In `tests/core/test_atomic_state_patches.py`, add a focused In `tests/core/test_atomic_state_patches.py`, add a focused
`apply_output_bindings` regression where one local source is bound to two `apply_output_bindings` regression where one local source is bound to two
@@ -322,7 +322,7 @@
test separately proves the same canonical list compiles. Do not only inspect test separately proves the same canonical list compiles. Do not only inspect
serialized draft JSON. serialized draft JSON.
- [ ] **Step 9: Run API and runtime tests** - [x] **Step 9: Run API and runtime tests**
Run: Run:
@@ -332,7 +332,7 @@
Expected: PASS. Expected: PASS.
- [ ] **Step 10: Commit Task 1** - [x] **Step 10: Commit Task 1**
```bash ```bash
git add src/wf_api/draft_authoring.py src/wf_api/surface.py src/wf_api/service.py tests/wf_api/test_drafts_service.py tests/core/test_atomic_state_patches.py git add src/wf_api/draft_authoring.py src/wf_api/surface.py src/wf_api/service.py tests/wf_api/test_drafts_service.py tests/core/test_atomic_state_patches.py
@@ -365,7 +365,7 @@
and remote client method `set_step_output_bindings(...)`. and remote client method `set_step_output_bindings(...)`.
- [ ] **Step 1: Write failing RPC application tests** - [x] **Step 1: Write failing RPC application tests**
Add a request containing duplicate sources and ordered distinct targets: Add a request containing duplicate sources and ordered distinct targets:
@@ -390,7 +390,7 @@
marker. These must return JSON-RPC invalid-params errors without invoking the marker. These must return JSON-RPC invalid-params errors without invoking the
semantic method. semantic method.
- [ ] **Step 2: Write failing remote client tests** - [x] **Step 2: Write failing remote client tests**
Call the typed client with two `OutputBinding` values sharing a source. Assert Call the typed client with two `OutputBinding` values sharing a source. Assert
the recorded wire method and JSON payload exactly: the recorded wire method and JSON payload exactly:
@@ -405,7 +405,7 @@
] ]
``` ```
- [ ] **Step 3: Run RPC tests and confirm RED** - [x] **Step 3: Run RPC tests and confirm RED**
```bash ```bash
uv run pytest tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py -q -k "step_output" uv run pytest tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py -q -k "step_output"
@@ -413,13 +413,13 @@
Expected: unknown method/model/client failures. Expected: unknown method/model/client failures.
- [ ] **Step 4: Add the typed parameter model and exports** - [x] **Step 4: Add the typed parameter model and exports**
Import `OutputBinding` in `models.py`, define Import `OutputBinding` in `models.py`, define
`SetStepOutputBindingsParams`, and add it to `wf_transport_rpc_http.__init__` `SetStepOutputBindingsParams`, and add it to `wf_transport_rpc_http.__init__`
imports and `__all__`. imports and `__all__`.
- [ ] **Step 5: Register the JSON-RPC method** - [x] **Step 5: Register the JSON-RPC method**
In `methods/drafts.py`, register: In `methods/drafts.py`, register:
@@ -442,12 +442,12 @@
Follow the existing decorator signature exactly if it differs from this Follow the existing decorator signature exactly if it differs from this
abbreviated example. abbreviated example.
- [ ] **Step 6: Add the remote client method** - [x] **Step 6: Add the remote client method**
Mirror `set_step_input_bindings` and serialize each binding with Mirror `set_step_input_bindings` and serialize each binding with
`model_dump(mode="json")`. Do not lower through `output_map`. `model_dump(mode="json")`. Do not lower through `output_map`.
- [ ] **Step 7: Run RPC tests** - [x] **Step 7: Run RPC tests**
```bash ```bash
uv run pytest tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py -q uv run pytest tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py -q
@@ -455,7 +455,7 @@
Expected: PASS. Expected: PASS.
- [ ] **Step 8: Commit Task 2** - [x] **Step 8: Commit Task 2**
```bash ```bash
git add src/wf_transport_rpc_http tests/wf_transport_rpc_http git add src/wf_transport_rpc_http tests/wf_transport_rpc_http
@@ -488,7 +488,7 @@
and MCP tool `wf.workflow.set_step_output_bindings`. and MCP tool `wf.workflow.set_step_output_bindings`.
- [ ] **Step 1: Write failing request-model tests** - [x] **Step 1: Write failing request-model tests**
Validate ordered fan-out and reject malformed canonical records: Validate ordered fan-out and reject malformed canonical records:
@@ -511,25 +511,25 @@
] ]
``` ```
- [ ] **Step 2: Write failing handler and discovery tests** - [x] **Step 2: Write failing handler and discovery tests**
Use the workflow-surface handler fake to assert the tool delegates once with Use the workflow-surface handler fake to assert the tool delegates once with
typed bindings in order. Add the tool name to server discovery/config tests typed bindings in order. Add the tool name to server discovery/config tests
and the always-visible proxy list assertion. and the always-visible proxy list assertion.
- [ ] **Step 3: Run focused MCP tests and confirm RED** - [x] **Step 3: Run focused MCP tests and confirm RED**
```bash ```bash
uv run pytest tests/wf_mcp/workflow_surface/test_drafts.py tests/wf_mcp/server/test_tools.py tests/wf_mcp/server/test_config.py -q -k "output_bindings or tools or config" uv run pytest tests/wf_mcp/workflow_surface/test_drafts.py tests/wf_mcp/server/test_tools.py tests/wf_mcp/server/test_config.py -q -k "output_bindings or tools or config"
``` ```
- [ ] **Step 4: Add the MCP request model** - [x] **Step 4: Add the MCP request model**
Define `SetStepOutputBindingsRequest` beside the map request and describe it Define `SetStepOutputBindingsRequest` beside the map request and describe it
as complete ordered replacement. Reuse `DraftOutputBindings`; do not define a as complete ordered replacement. Reuse `DraftOutputBindings`; do not define a
second union or path-map type. second union or path-map type.
- [ ] **Step 5: Register the MCP tool** - [x] **Step 5: Register the MCP tool**
Add: Add:
@@ -556,12 +556,12 @@
Follow local registration and result-conversion conventions exactly. Follow local registration and result-conversion conventions exactly.
- [ ] **Step 6: Pin the tool in proxy discovery** - [x] **Step 6: Pin the tool in proxy discovery**
Add `wf.workflow.set_step_output_bindings` beside input bindings in Add `wf.workflow.set_step_output_bindings` beside input bindings in
`_SEARCH_ALWAYS_VISIBLE_TOOL_NAMES`. `_SEARCH_ALWAYS_VISIBLE_TOOL_NAMES`.
- [ ] **Step 7: Run MCP tests** - [x] **Step 7: Run MCP tests**
```bash ```bash
uv run pytest tests/wf_mcp/workflow_surface/test_drafts.py tests/wf_mcp/server/test_tools.py tests/wf_mcp/server/test_config.py -q uv run pytest tests/wf_mcp/workflow_surface/test_drafts.py tests/wf_mcp/server/test_tools.py tests/wf_mcp/server/test_config.py -q
@@ -569,7 +569,7 @@
Expected: PASS. Expected: PASS.
- [ ] **Step 8: Commit Task 3** - [x] **Step 8: Commit Task 3**
```bash ```bash
git add src/wf_mcp tests/wf_mcp git add src/wf_mcp tests/wf_mcp
@@ -600,7 +600,7 @@
- Keeps: `wf draft set-output`; no new command name. - Keeps: `wf draft set-output`; no new command name.
- [ ] **Step 1: Write failing parser tests** - [x] **Step 1: Write failing parser tests**
Add tests proving repeated sources remain separate and file order is exact: Add tests proving repeated sources remain separate and file order is exact:
@@ -621,7 +621,7 @@
invalid local source syntax, and non-state targets as concise invalid local source syntax, and non-state targets as concise
`typer.BadParameter` errors. `typer.BadParameter` errors.
- [ ] **Step 2: Write failing local command tests** - [x] **Step 2: Write failing local command tests**
Cover: Cover:
@@ -634,7 +634,7 @@
- `--merge --map` dispatching to `set_step_output_map` only; - `--merge --map` dispatching to `set_step_output_map` only;
- duplicate-source fan-out dispatching to `set_step_output_bindings` only. - duplicate-source fan-out dispatching to `set_step_output_bindings` only.
- [ ] **Step 3: Write failing remote-target tests** - [x] **Step 3: Write failing remote-target tests**
Run the same repeated-source and file modes with `--target`. Assert the RPC Run the same repeated-source and file modes with `--target`. Assert the RPC
method is exactly method is exactly
@@ -642,13 +642,13 @@
order preserved. Retain one compatibility `--merge` assertion for order preserved. Retain one compatibility `--merge` assertion for
`set_step_output_map`. `set_step_output_map`.
- [ ] **Step 4: Run focused CLI tests and confirm RED** - [x] **Step 4: Run focused CLI tests and confirm RED**
```bash ```bash
uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py -q -k "set_output" uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py -q -k "set_output"
``` ```
- [ ] **Step 5: Add output binding parsers** - [x] **Step 5: Add output binding parsers**
In `draft_options.py`, import `OutputBinding`, add a In `draft_options.py`, import `OutputBinding`, add a
`TypeAdapter(list[OutputBinding])`, parse ordered flags directly rather than `TypeAdapter(list[OutputBinding])`, parse ordered flags directly rather than
@@ -682,7 +682,7 @@
`parse_step_output_bindings_file` validates `parse_json_file(...)` through the `parse_step_output_bindings_file` validates `parse_json_file(...)` through the
adapter exactly as the input file parser does. adapter exactly as the input file parser does.
- [ ] **Step 6: Rework `wf draft set-output` dispatch** - [x] **Step 6: Rework `wf draft set-output` dispatch**
Add `--bindings-file: Path | None` and `--clear: bool`. Use this mode matrix: Add `--bindings-file: Path | None` and `--clear: bool`. Use this mode matrix:
@@ -707,7 +707,7 @@
bindings and `set_step_output_bindings`. The no-flags case must no longer bindings and `set_step_output_bindings`. The no-flags case must no longer
silently clear outputs; clearing requires `--clear`. silently clear outputs; clearing requires `--clear`.
- [ ] **Step 7: Update command help tests** - [x] **Step 7: Update command help tests**
Pin direction and semantics: Pin direction and semantics:
@@ -718,7 +718,7 @@
--merge compatibility-only and potentially lossy --merge compatibility-only and potentially lossy
``` ```
- [ ] **Step 8: Run CLI tests** - [x] **Step 8: Run CLI tests**
```bash ```bash
uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py -q uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py -q
@@ -726,7 +726,7 @@
Expected: PASS. Expected: PASS.
- [ ] **Step 9: Commit Task 4** - [x] **Step 9: Commit Task 4**
```bash ```bash
git add src/wf_cli tests/wf_cli git add src/wf_cli tests/wf_cli
@@ -751,7 +751,7 @@
- Consumes: all completed implementation tasks and their verified command names. - Consumes: all completed implementation tasks and their verified command names.
- Produces: current user/agent guidance, accurate issue state, archived checked plan, and a final verification report. - Produces: current user/agent guidance, accurate issue state, archived checked plan, and a final verification report.
- [ ] **Step 1: Update issue language without falsely closing map loss** - [x] **Step 1: Update issue language without falsely closing map loss**
Keep the combined issue unchecked and revise it to state: Keep the combined issue unchecked and revise it to state:
@@ -764,7 +764,7 @@
Leave workflow-output literals, nested workflow-output projection, focused Leave workflow-output literals, nested workflow-output projection, focused
step updates, and TypeScript parity unchecked. step updates, and TypeScript parity unchecked.
- [ ] **Step 2: Update CLI and agent documentation** - [x] **Step 2: Update CLI and agent documentation**
Replace descriptions that say `set-output` replaces a map with canonical-list Replace descriptions that say `set-output` replaces a map with canonical-list
language. Include examples for repeated-source fan-out, file round-trip, language. Include examples for repeated-source fan-out, file round-trip,
@@ -787,13 +787,13 @@
Explicitly warn that `--merge --map` is compatibility-only and may collapse Explicitly warn that `--merge --map` is compatibility-only and may collapse
existing fan-out. existing fan-out.
- [ ] **Step 3: Update RPC/MCP operation inventories** - [x] **Step 3: Update RPC/MCP operation inventories**
Add `workflow.draft_workspaces.set_step_output_bindings` and Add `workflow.draft_workspaces.set_step_output_bindings` and
`wf.workflow.set_step_output_bindings` to user-facing inventories and examples `wf.workflow.set_step_output_bindings` to user-facing inventories and examples
near their input counterparts. near their input counterparts.
- [ ] **Step 4: Run focused matrix verification** - [x] **Step 4: Run focused matrix verification**
```bash ```bash
uv run pytest \ uv run pytest \
@@ -810,7 +810,7 @@
Expected: PASS with only already-known dependency deprecation warnings. Expected: PASS with only already-known dependency deprecation warnings.
- [ ] **Step 5: Run static verification** - [x] **Step 5: Run static verification**
```bash ```bash
uv run ruff check uv run ruff check
@@ -821,13 +821,13 @@
Expected: all clean. Expected: all clean.
- [ ] **Step 6: Run independent review** - [x] **Step 6: Run independent review**
Use the repository code-review skill against the pre-slice commit. Fix every Use the repository code-review skill against the pre-slice commit. Fix every
Critical or Important finding. Record Minor deferrals with concrete reasons Critical or Important finding. Record Minor deferrals with concrete reasons
in the final report. in the final report.
- [ ] **Step 7: Update roadmap and archive this plan** - [x] **Step 7: Update roadmap and archive this plan**
Add a completed roadmap entry linking to: Add a completed roadmap entry linking to:
@@ -838,14 +838,14 @@
Check every completed plan box, move the plan under `docs/historical/`, and Check every completed plan box, move the plan under `docs/historical/`, and
verify no live link still points to its old location. verify no live link still points to its old location.
- [ ] **Step 8: Commit documentation and completion state** - [x] **Step 8: Commit documentation and completion state**
```bash ```bash
git add ISSUES.md skills docs git add ISSUES.md skills docs
git commit -m "docs: complete atomic step output bindings" git commit -m "docs: complete atomic step output bindings"
``` ```
- [ ] **Step 9: Final repository check** - [x] **Step 9: Final repository check**
```bash ```bash
git status --short git status --short
+3 -1
View File
@@ -151,6 +151,8 @@ Focused repair helpers:
- `wf.workflow.set_draft_name` - `wf.workflow.set_draft_name`
- `wf.workflow.set_draft_route` - `wf.workflow.set_draft_route`
- `wf.workflow.set_step_input_bindings`
- `wf.workflow.set_step_output_bindings`
- `wf.workflow.set_step_input_map` - `wf.workflow.set_step_input_map`
- `wf.workflow.set_step_output_map` - `wf.workflow.set_step_output_map`
@@ -543,7 +545,7 @@ resending the full draft each turn.
| Fetch current draft workspace | `wf.workflow.get_draft_workspace` | | Fetch current draft workspace | `wf.workflow.get_draft_workspace` |
| Patch current draft workspace | `wf.workflow.patch_draft_workspace` | | Patch current draft workspace | `wf.workflow.patch_draft_workspace` |
| Refresh validation without changing revision | `wf.workflow.validate_draft_workspace` | | Refresh validation without changing revision | `wf.workflow.validate_draft_workspace` |
| Change common draft fields without JSON Patch | `wf.workflow.set_draft_name`, `wf.workflow.set_draft_route`, `wf.workflow.set_step_input_map`, `wf.workflow.set_step_output_map` | | Change common draft fields without JSON Patch | `wf.workflow.set_draft_name`, `wf.workflow.set_draft_route`, `wf.workflow.set_step_input_bindings`, `wf.workflow.set_step_output_bindings`, `wf.workflow.set_step_input_map`, `wf.workflow.set_step_output_map` |
| Save final workspace as artifact | `wf.workflow.create_artifact_from_workspace` | | Save final workspace as artifact | `wf.workflow.create_artifact_from_workspace` |
| Save final workspace as callable wrapper | `wf.workflow.create_wrapper_from_workspace` | | Save final workspace as callable wrapper | `wf.workflow.create_wrapper_from_workspace` |
| Clean up a draft workspace | `wf.workflow.delete_draft_workspace` | | Clean up a draft workspace | `wf.workflow.delete_draft_workspace` |
+4 -3
View File
@@ -312,9 +312,10 @@ For the copy-less wrapper authoring path, use:
`wrapper_hints`. `wrapper_hints`.
2. `wf.workflow.create_draft_workspace_from_capability` to create a patchable 2. `wf.workflow.create_draft_workspace_from_capability` to create a patchable
draft workspace from those hints. draft workspace from those hints.
3. Focused patch helpers such as `wf.workflow.set_step_input_map`, 3. Focused patch helpers such as `wf.workflow.set_step_input_bindings`,
`wf.workflow.set_step_output_map`, and `wf.workflow.set_draft_route` to fix `wf.workflow.set_step_output_bindings`, their compatibility map adapters,
low-confidence hints or explicit `missing_decisions`. and `wf.workflow.set_draft_route` to fix low-confidence hints or explicit
`missing_decisions`.
4. `wf.workflow.validate_draft_workspace` to refresh diagnostics. 4. `wf.workflow.validate_draft_workspace` to refresh diagnostics.
5. `wf.workflow.create_wrapper_from_workspace` to save the wrapper artifact. 5. `wf.workflow.create_wrapper_from_workspace` to save the wrapper artifact.
6. `wf.workflow.call_capability` with `workflow.<artifact_id>.v<version>` to 6. `wf.workflow.call_capability` with `workflow.<artifact_id>.v<version>` to
+23 -2
View File
@@ -48,6 +48,8 @@ wf draft set-input <workspace_id> --revision <n> --step <step_id> --bindings-fil
wf draft set-input <workspace_id> --revision <n> --step <step_id> --clear wf draft set-input <workspace_id> --revision <n> --step <step_id> --clear
wf draft set-input <workspace_id> --revision <n> --step <step_id> --merge --map input.other=other wf draft set-input <workspace_id> --revision <n> --step <step_id> --merge --map input.other=other
wf draft set-output <workspace_id> --revision <n> --step <step_id> --map text=state.text wf draft set-output <workspace_id> --revision <n> --step <step_id> --map text=state.text
wf draft set-output <workspace_id> --revision <n> --step <step_id> --bindings-file bindings.json
wf draft set-output <workspace_id> --revision <n> --step <step_id> --clear
wf draft set-output <workspace_id> --revision <n> --step <step_id> --merge --map other=state.other wf draft set-output <workspace_id> --revision <n> --step <step_id> --merge --map other=state.other
wf draft set-workflow-output <workspace_id> --revision <n> --map state.value=result wf draft set-workflow-output <workspace_id> --revision <n> --map state.value=result
wf draft set-workflow-output <workspace_id> --revision <n> --merge --map state.other=other wf draft set-workflow-output <workspace_id> --revision <n> --merge --map state.other=other
@@ -147,8 +149,27 @@ wf draft set-input WS --revision 5 --step publish \
wf draft set-input WS --revision 6 --step publish --clear wf draft set-input WS --revision 6 --step publish --clear
``` ```
For `draft set-output`, repeated `--map` flags still define the complete For `draft set-output`, repeated `--map` flags define the complete ordered
replacement map. Pass `--merge` only when deliberately using that map adapter. canonical binding list and preserve repeated-source fan-out. The canonical
file form is lossless, and `--clear` explicitly replaces the list with no
bindings:
```bash
wf draft set-output WS --revision 4 --step analyze \
--map report.title=state.report.title \
--map report.title=state.audit.title
wf draft inspect WS --include-draft |
jq '.draft.steps.analyze.output' > output-bindings.json
wf draft set-output WS --revision 5 --step analyze \
--bindings-file output-bindings.json
wf draft set-output WS --revision 6 --step analyze --clear
```
`--merge --map` is compatibility-only and may collapse existing fan-out. Use
it only when a lossy map edit is acceptable.
Prefer `draft bind` when a capability step binding also needs schema Prefer `draft bind` when a capability step binding also needs schema
projection. Use `input/state -> local` for step inputs and `local -> projection. Use `input/state -> local` for step inputs and `local ->
@@ -85,6 +85,7 @@ Prefer focused helpers over JSON Patch for common edits:
- `set_draft_name` - `set_draft_name`
- `set_draft_route` - `set_draft_route`
- `set_step_input_map` - `set_step_input_map`
- `set_step_output_bindings`
- `set_step_output_map` - `set_step_output_map`
- `set_workflow_output_map` - `set_workflow_output_map`
- `bind_draft` - `bind_draft`
@@ -105,6 +106,8 @@ wf draft set-input <workspace_id> --revision <n> --step <step_id> --bindings-fil
wf draft set-input <workspace_id> --revision <n> --step <step_id> --clear wf draft set-input <workspace_id> --revision <n> --step <step_id> --clear
wf draft set-input <workspace_id> --revision <n> --step <step_id> --merge --map input.other=other wf draft set-input <workspace_id> --revision <n> --step <step_id> --merge --map input.other=other
wf draft set-output <workspace_id> --revision <n> --step <step_id> --map text=state.text wf draft set-output <workspace_id> --revision <n> --step <step_id> --map text=state.text
wf draft set-output <workspace_id> --revision <n> --step <step_id> --bindings-file bindings.json
wf draft set-output <workspace_id> --revision <n> --step <step_id> --clear
wf draft set-output <workspace_id> --revision <n> --step <step_id> --merge --map other=state.other wf draft set-output <workspace_id> --revision <n> --step <step_id> --merge --map other=state.other
wf draft set-workflow-output <workspace_id> --revision <n> --map state.value=result wf draft set-workflow-output <workspace_id> --revision <n> --map state.value=result
wf draft set-workflow-output <workspace_id> --revision <n> --merge --map state.other=other wf draft set-workflow-output <workspace_id> --revision <n> --merge --map state.other=other
@@ -156,9 +159,28 @@ survive. Existing literal bindings are retained during a map-only merge.
maps to graph target `state.text`. maps to graph target `state.text`.
Without `--merge`, `set-input` replaces the whole ordered binding list; Without `--merge`, `set-input` replaces the whole ordered binding list;
`set-output` and `set-workflow-output` replace their whole maps. Use repeated `set-output` replaces its complete ordered canonical binding list. Repeated
flags in one command for a complete replacement. Use `--merge` only for the sources are valid fan-out when their state targets differ. Use the canonical
compatibility map adapters. file form for a lossless round-trip, or `--clear` to replace the list with no
bindings:
```bash
wf draft set-output WS --revision 4 --step analyze \
--map report.title=state.report.title \
--map report.title=state.audit.title
wf draft inspect WS --include-draft |
jq '.draft.steps.analyze.output' > output-bindings.json
wf draft set-output WS --revision 5 --step analyze \
--bindings-file output-bindings.json
wf draft set-output WS --revision 6 --step analyze --clear
```
`--merge --map` is compatibility-only and may collapse existing fan-out. Use
it only when a lossy map edit is acceptable. `set-workflow-output` retains its
map replacement behavior and is a separate workflow-boundary operation.
`bind input.title -> local.report.title` is schema-aware and idempotent when `bind input.title -> local.report.title` is schema-aware and idempotent when
`input.title` is already declared. Bind names both rooted endpoints explicitly. `input.title` is already declared. Bind names both rooted endpoints explicitly.
@@ -16,10 +16,10 @@ validated, runnable deployment.
5. Inspect/patch/validate the workspace until valid. 5. Inspect/patch/validate the workspace until valid.
- Use focused CLI commands (`set-name`, `set-route`, `set-input`, `set-output`) - Use focused CLI commands (`set-name`, `set-route`, `set-input`, `set-output`)
for common edits. for common edits.
- `set-input` replaces its ordered canonical binding list; `set-output` - `set-input` and `set-output` replace their ordered canonical binding lists.
replaces its map. `set-input --merge` is compatibility-only and cannot Repeated sources preserve fan-out to distinct targets. The `--merge`
add literals or preserve canonical ordering and repeated-source fan-out; variants are compatibility-only and cannot preserve canonical ordering or
existing literals are retained. repeated-source fan-out; existing literals are retained for input merges.
- Before mapping into a new workflow input, state, or output field, prefer - Before mapping into a new workflow input, state, or output field, prefer
`wf draft bind --from ... --to ...` when it should mirror a capability `wf draft bind --from ... --to ...` when it should mirror a capability
local input/output property. It declares the matching schema and merges local input/output property. It declares the matching schema and merges