docs: complete atomic workflow output bindings
This commit is contained in:
@@ -23,11 +23,11 @@
|
||||
- [ ] Compatibility step input/output maps can still collapse valid canonical
|
||||
fan-out bindings. Canonical input and output replacement preserve ordered
|
||||
fan-out, but later compatibility-map merges remain inherently lossy.
|
||||
- [ ] Focused workflow-output authoring cannot add or update literal output
|
||||
bindings even though `WorkflowDraft.output` accepts canonical value bindings.
|
||||
- [ ] Workflow output schema projection skips nested sources such as
|
||||
`state.report.title`, leaving callers to patch the output schema manually even
|
||||
when the nested source schema is already declared.
|
||||
- [x] Focused workflow-output authoring supports literal output bindings through
|
||||
canonical Python, JSON-RPC, MCP, and CLI replacement surfaces.
|
||||
- [x] Workflow-output replacement projects nested `input.*` and `state.*`
|
||||
source schemas, including local references, into missing nested public output
|
||||
targets without requiring raw schema patches.
|
||||
- [x] CLI help and agent instructions describe step-input targets as bare local
|
||||
fields and do not document the nested composition behavior already supported
|
||||
by the canonical runtime model.
|
||||
|
||||
@@ -590,9 +590,16 @@ clear operator feedback before adding more architecture.
|
||||
Implementation:
|
||||
[`draft remove commands`](historical/superpowers/plans/2026-06-28-draft-remove-commands.md).
|
||||
- Completed: `wf draft set-workflow-output` and full-stack API/RPC/CLI support
|
||||
for editing top-level workflow output bindings. Accepts repeatable `--map`
|
||||
and `--merge` flag. Implementation:
|
||||
for editing top-level workflow output bindings. The compatibility map
|
||||
adapter remains available for existing callers. Implementation:
|
||||
[`set-workflow-output API/RPC/CLI`](historical/superpowers/plans/2026-06-29-set-workflow-output.md).
|
||||
- Completed: canonical workflow-output replacement now preserves ordered
|
||||
path/value bindings across Python, JSON-RPC, MCP, and CLI; nested input/state
|
||||
sources can project missing output schemas, while literals and `context.*`
|
||||
require declared targets. Empty replacement restores implicit same-name state
|
||||
fallback; compatibility `--merge --map` remains intentionally lossy.
|
||||
Implementation:
|
||||
[`atomic workflow output bindings`](historical/superpowers/plans/2026-07-23-atomic-workflow-output-bindings.md).
|
||||
- Completed: challenge-driven output UX polish makes `set-workflow-output`
|
||||
project missing top-level output schema fields from declared `input.*` and
|
||||
`state.*` sources, and challenge prompt templates now always include
|
||||
|
||||
+39
-39
@@ -1,6 +1,6 @@
|
||||
# Atomic Workflow Output Bindings 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.
|
||||
> **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 (`- [x]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add one revision-checked canonical workflow-output binding replacement operation across Python, JSON-RPC, MCP, and CLI, with nested schema projection, literal validation, and unchanged empty-list fallback semantics.
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
- Produces: `WorkflowDraftAuthoringApi.set_workflow_output_bindings(*, workspace_id: str, revision: int, bindings: Sequence[InputBinding]) -> dict[str, Any]`.
|
||||
- Produces: `validate_json_value_at_schema_path(..., schema_label: str = "capability input schema") -> None`, preserving existing callers through the default.
|
||||
|
||||
- [ ] **Step 1: Write failing neutral-label and referenced-target schema tests**
|
||||
- [x] **Step 1: Write failing neutral-label and referenced-target schema tests**
|
||||
|
||||
Add tests in `tests/wf_api/test_schema_projection.py` that pin the shared helper contract:
|
||||
|
||||
@@ -84,7 +84,7 @@ def test_project_schema_path_updates_output_target_through_local_ref() -> None:
|
||||
|
||||
The second test protects the target-side `$ref` behavior introduced by the step-output slice while this operation begins relying on it directly.
|
||||
|
||||
- [ ] **Step 2: Run the schema tests and verify the neutral label test fails**
|
||||
- [x] **Step 2: Run the schema tests and verify the neutral label test fails**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -95,7 +95,7 @@ uv run pytest tests/wf_api/test_schema_projection.py -q
|
||||
Expected: the existing referenced-target test passes and the new
|
||||
`schema_label` call fails because the helper does not yet accept that keyword.
|
||||
|
||||
- [ ] **Step 3: Generalize the literal-validation diagnostic label**
|
||||
- [x] **Step 3: Generalize the literal-validation diagnostic label**
|
||||
|
||||
Change `validate_json_value_at_schema_path(...)` in
|
||||
`src/wf_api/schema_projection.py` without adding a second validator:
|
||||
@@ -126,7 +126,7 @@ def validate_json_value_at_schema_path(
|
||||
|
||||
Run the schema test file again. Expected: PASS.
|
||||
|
||||
- [ ] **Step 4: Write failing canonical authoring tests**
|
||||
- [x] **Step 4: Write failing canonical authoring tests**
|
||||
|
||||
In `tests/wf_api/test_drafts_service.py`, add a helper draft whose input, state,
|
||||
and output schemas contain nested fields and whose output list initially is
|
||||
@@ -262,7 +262,7 @@ async def test_set_workflow_output_bindings_rejects_without_mutation(
|
||||
# assert the complete inspected workspace still equals the snapshot.
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Run focused authoring tests and verify they fail**
|
||||
- [x] **Step 5: Run focused authoring tests and verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -273,7 +273,7 @@ uv run pytest tests/wf_api/test_drafts_service.py -q -k "workflow_output_binding
|
||||
Expected: FAIL because `WorkflowDraftAuthoringApi` has no canonical workflow
|
||||
output method.
|
||||
|
||||
- [ ] **Step 6: Implement the canonical authoring operation**
|
||||
- [x] **Step 6: Implement the canonical authoring operation**
|
||||
|
||||
In `src/wf_api/draft_authoring.py`, import `Mapping`, `InputBinding`,
|
||||
`InputPathBinding`, `InputValueBinding`, `GraphSourcePath`, `LocalPath`, and the
|
||||
@@ -422,7 +422,7 @@ Do not copy this mechanically if an existing helper provides the same behavior;
|
||||
reuse it. Preserve the specified validation order and wrap projection failures
|
||||
with `bindings[index]` context.
|
||||
|
||||
- [ ] **Step 7: Add compile-and-execute coverage**
|
||||
- [x] **Step 7: Add compile-and-execute coverage**
|
||||
|
||||
Add a test that creates a valid draft, invokes the new authoring method, compiles
|
||||
with `compile_draft_workspace`, runs through `WfMcpService.run_workflow_from_plan`,
|
||||
@@ -441,7 +441,7 @@ Add a second execution assertion for a cleared explicit list: declare a
|
||||
top-level output field matching state, clear bindings, compile/run, and prove the
|
||||
existing implicit fallback still returns that state field.
|
||||
|
||||
- [ ] **Step 8: Run Task 1 verification**
|
||||
- [x] **Step 8: Run Task 1 verification**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -454,7 +454,7 @@ uv run basedpyright --level error src/wf_api/schema_projection.py src/wf_api/dra
|
||||
Expected: all pass. If the installed basedpyright does not accept file paths,
|
||||
run the repository-wide `uv run basedpyright --level error` instead.
|
||||
|
||||
- [ ] **Step 9: Review and commit Task 1**
|
||||
- [x] **Step 9: Review and commit Task 1**
|
||||
|
||||
Review the Task 1 diff against the spec, especially root-target equality,
|
||||
context behavior, stale-revision precedence, and no mutation on errors. Then:
|
||||
@@ -482,7 +482,7 @@ git commit -m "feat: replace canonical workflow output bindings"
|
||||
- Consumes: Task 1's `WorkflowDraftAuthoringApi.set_workflow_output_bindings(...)`.
|
||||
- Produces: `WorkflowApiSurface.set_workflow_output_bindings(...)`, `WorkflowApi.set_workflow_output_bindings(...)`, `SetWorkflowOutputBindingsParams`, JSON-RPC method `workflow.draft_workspaces.set_workflow_output_bindings`, and `RpcWorkflowApiClient.set_workflow_output_bindings(...)`.
|
||||
|
||||
- [ ] **Step 1: Write failing RPC model and endpoint tests**
|
||||
- [x] **Step 1: Write failing RPC model and endpoint tests**
|
||||
|
||||
In `tests/wf_transport_rpc_http/test_app.py`, add an end-to-end request using a
|
||||
real local server:
|
||||
@@ -528,7 +528,7 @@ stored list preserves a path binding followed by a value binding. Add malformed
|
||||
requests proving `path` plus `value`, missing `target`, extra fields, and invalid
|
||||
roots fail with JSON-RPC `-32602` before semantic logic.
|
||||
|
||||
- [ ] **Step 2: Write the failing remote client test**
|
||||
- [x] **Step 2: Write the failing remote client test**
|
||||
|
||||
In `tests/wf_transport_rpc_http/test_client.py`, add:
|
||||
|
||||
@@ -566,7 +566,7 @@ async def test_rpc_client_set_workflow_output_bindings_preserves_union_order(
|
||||
Adapt the fixture names to the existing client test harness; keep the assertions
|
||||
field-level.
|
||||
|
||||
- [ ] **Step 3: Run RPC tests and verify they fail**
|
||||
- [x] **Step 3: Run RPC tests and verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -576,7 +576,7 @@ uv run pytest tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_htt
|
||||
|
||||
Expected: FAIL because the params model, endpoint, and client method are absent.
|
||||
|
||||
- [ ] **Step 4: Add the public surface and local service delegation**
|
||||
- [x] **Step 4: Add the public surface and local service delegation**
|
||||
|
||||
Add this method to `WorkflowApiSurface` in `src/wf_api/surface.py`:
|
||||
|
||||
@@ -610,7 +610,7 @@ async def set_workflow_output_bindings(
|
||||
Keep `set_workflow_output_map(...)` unchanged and adjacent as the compatibility
|
||||
surface.
|
||||
|
||||
- [ ] **Step 5: Add the typed RPC request, endpoint, and client**
|
||||
- [x] **Step 5: Add the typed RPC request, endpoint, and client**
|
||||
|
||||
In `src/wf_transport_rpc_http/models.py`:
|
||||
|
||||
@@ -667,7 +667,7 @@ async def set_workflow_output_bindings(
|
||||
Export `SetWorkflowOutputBindingsParams` from
|
||||
`src/wf_transport_rpc_http/__init__.py` in both import and `__all__` lists.
|
||||
|
||||
- [ ] **Step 6: Run Task 2 verification**
|
||||
- [x] **Step 6: Run Task 2 verification**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -678,7 +678,7 @@ uv run basedpyright --level error
|
||||
|
||||
Expected: all pass and every `WorkflowApiSurface` implementation conforms.
|
||||
|
||||
- [ ] **Step 7: Review and commit Task 2**
|
||||
- [x] **Step 7: Review and commit Task 2**
|
||||
|
||||
Review request validation, canonical order, and local/remote interface parity.
|
||||
Then:
|
||||
@@ -704,7 +704,7 @@ git commit -m "feat: expose workflow output bindings over rpc"
|
||||
- Consumes: Task 2's public `set_workflow_output_bindings(...)` method and the existing `DraftInputBindings` alias.
|
||||
- Produces: `SetWorkflowOutputBindingsRequest` and MCP tool `wf.workflow.set_workflow_output_bindings`.
|
||||
|
||||
- [ ] **Step 1: Write failing MCP request-model tests**
|
||||
- [x] **Step 1: Write failing MCP request-model tests**
|
||||
|
||||
In `tests/wf_mcp/workflow_surface/test_drafts.py`, add:
|
||||
|
||||
@@ -730,7 +730,7 @@ def test_set_workflow_output_bindings_request_preserves_union_order() -> None:
|
||||
Add a malformed-record test with both `path` and `value`, and assert Pydantic
|
||||
rejects the extra union field.
|
||||
|
||||
- [ ] **Step 2: Write failing tool-registration and invocation tests**
|
||||
- [x] **Step 2: Write failing tool-registration and invocation tests**
|
||||
|
||||
Extend the fake handler in `tests/wf_mcp/server/test_tools.py` with a call log for
|
||||
`set_workflow_output_bindings`. Assert the tool inventory includes the new name,
|
||||
@@ -760,7 +760,7 @@ assert handler.calls[-1]["bindings"][1].value == "markdown"
|
||||
Update config/discovery expectations so the public tool count/name inventory is
|
||||
explicit rather than only asserting a count.
|
||||
|
||||
- [ ] **Step 3: Run MCP tests and verify they fail**
|
||||
- [x] **Step 3: Run MCP tests and verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -770,7 +770,7 @@ uv run pytest tests/wf_mcp/workflow_surface/test_drafts.py tests/wf_mcp/server/t
|
||||
|
||||
Expected: FAIL because the request and tool do not exist.
|
||||
|
||||
- [ ] **Step 4: Add the MCP request and tool**
|
||||
- [x] **Step 4: Add the MCP request and tool**
|
||||
|
||||
In `src/wf_mcp/workflow_surface/models.py`:
|
||||
|
||||
@@ -809,7 +809,7 @@ async def set_workflow_output_bindings(
|
||||
Add the new name to the explicit workflow proxy allow-list in
|
||||
`src/wf_mcp/proxy/runtime.py`. Preserve the existing map tool.
|
||||
|
||||
- [ ] **Step 5: Run Task 3 verification**
|
||||
- [x] **Step 5: Run Task 3 verification**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -820,7 +820,7 @@ uv run basedpyright --level error
|
||||
|
||||
Expected: all pass.
|
||||
|
||||
- [ ] **Step 6: Review and commit Task 3**
|
||||
- [x] **Step 6: Review and commit Task 3**
|
||||
|
||||
Review actual tool invocation, discovery visibility, request validation, and
|
||||
ordered union preservation. Then:
|
||||
@@ -844,7 +844,7 @@ git commit -m "feat: expose workflow output bindings to mcp"
|
||||
- Consumes: Task 2's local/remote `set_workflow_output_bindings(...)` method.
|
||||
- Produces: canonical `wf draft set-workflow-output` modes `--map`, `--value`, `--bindings-file`, and `--clear`; preserves compatibility-only `--merge --map`.
|
||||
|
||||
- [ ] **Step 1: Write failing parser tests**
|
||||
- [x] **Step 1: Write failing parser tests**
|
||||
|
||||
In `tests/wf_cli/test_app.py`, add parser tests proving:
|
||||
|
||||
@@ -874,7 +874,7 @@ Add bindings-file tests for a mixed canonical array and malformed unions. Pin
|
||||
compact `typer.BadParameter` messages for invalid graph roots, `local.`-prefixed
|
||||
targets, invalid JSON, and non-array files.
|
||||
|
||||
- [ ] **Step 2: Extract shared input-shaped CLI parsers**
|
||||
- [x] **Step 2: Extract shared input-shaped CLI parsers**
|
||||
|
||||
In `src/wf_cli/commands/draft_options.py`, avoid duplicating the step-input
|
||||
parser. Extract private helpers parameterized only by audience wording:
|
||||
@@ -931,7 +931,7 @@ def parse_workflow_output_bindings_file(path: Path) -> list[InputBinding]:
|
||||
|
||||
Do not change accepted step-input syntax or its existing error assertions.
|
||||
|
||||
- [ ] **Step 3: Write failing command tests**
|
||||
- [x] **Step 3: Write failing command tests**
|
||||
|
||||
Add local CLI tests that use a fake handler with separate canonical and map call
|
||||
logs. Cover:
|
||||
@@ -981,7 +981,7 @@ assert the captured method is
|
||||
`workflow.draft_workspaces.set_workflow_output_bindings` with the exact ordered
|
||||
mixed binding list. Keep a remote compatibility test for `--merge --map`.
|
||||
|
||||
- [ ] **Step 4: Run CLI tests and verify they fail**
|
||||
- [x] **Step 4: Run CLI tests and verify they fail**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -991,7 +991,7 @@ uv run pytest tests/wf_cli/test_app.py tests/wf_cli/test_remote_target.py -q -k
|
||||
|
||||
Expected: parser tests or command tests fail because canonical modes are absent.
|
||||
|
||||
- [ ] **Step 5: Replace the command's default path while retaining compatibility**
|
||||
- [x] **Step 5: Replace the command's default path while retaining compatibility**
|
||||
|
||||
Update imports and the `set_workflow_output` Typer command in
|
||||
`src/wf_cli/commands/drafts.py`. Parse modes before loading context:
|
||||
@@ -1057,7 +1057,7 @@ Use assertions or explicit branches to satisfy basedpyright narrowing without
|
||||
`cast(Any, ...)`. Rewrite the docstring/help so `--clear` explicitly says it
|
||||
restores implicit same-name state fallback rather than promising empty output.
|
||||
|
||||
- [ ] **Step 6: Run Task 4 verification**
|
||||
- [x] **Step 6: Run Task 4 verification**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -1068,7 +1068,7 @@ uv run basedpyright --level error
|
||||
|
||||
Expected: all pass.
|
||||
|
||||
- [ ] **Step 7: Review and commit Task 4**
|
||||
- [x] **Step 7: Review and commit Task 4**
|
||||
|
||||
Review mode exclusivity, parsing-before-context, flag ordering, local/remote
|
||||
parity, and compatibility isolation. Then:
|
||||
@@ -1092,13 +1092,13 @@ git commit -m "feat: replace workflow output bindings from cli"
|
||||
- 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-23-atomic-workflow-output-bindings.md` to `docs/historical/superpowers/plans/2026-07-23-atomic-workflow-output-bindings.md`
|
||||
- Moved: `docs/superpowers/plans/2026-07-23-atomic-workflow-output-bindings.md` to `docs/historical/superpowers/plans/2026-07-23-atomic-workflow-output-bindings.md`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: verified behavior from Tasks 1-4.
|
||||
- Produces: current user/agent documentation, accurate issue state, completed roadmap entry, archived checked plan, and final review evidence.
|
||||
|
||||
- [ ] **Step 1: Update issue state without closing compatibility-map loss**
|
||||
- [x] **Step 1: Update issue state without closing compatibility-map loss**
|
||||
|
||||
In `ISSUES.md`:
|
||||
|
||||
@@ -1109,7 +1109,7 @@ In `ISSUES.md`:
|
||||
- state that canonical workflow-output replacement preserves path/value union
|
||||
order while `set_workflow_output_map` remains compatibility-only.
|
||||
|
||||
- [ ] **Step 2: Update live CLI and workflow docs**
|
||||
- [x] **Step 2: Update live CLI and workflow docs**
|
||||
|
||||
Update `docs/wf_cli.md` and `docs/workflow_drafts.md` with all canonical modes:
|
||||
|
||||
@@ -1140,7 +1140,7 @@ Update operation inventories in `docs/workflow_capabilities.md` and
|
||||
`workflow.draft_workspaces.set_workflow_output_bindings` and
|
||||
`wf.workflow.set_workflow_output_bindings`.
|
||||
|
||||
- [ ] **Step 3: Update agent instruction surfaces**
|
||||
- [x] **Step 3: Update agent instruction surfaces**
|
||||
|
||||
Update `skills/wf-cli/SKILL.md` and the two `wf-workflow` references with the
|
||||
same canonical examples and decision rule:
|
||||
@@ -1153,7 +1153,7 @@ round-trip. Use --merge --map only when a lossy compatibility edit is acceptable
|
||||
|
||||
Do not direct agents to implementation files or tests.
|
||||
|
||||
- [ ] **Step 4: Update roadmap and archive the checked plan**
|
||||
- [x] **Step 4: Update roadmap and archive the checked plan**
|
||||
|
||||
Add a completed milestone to `docs/current_roadmap.md` linking to:
|
||||
|
||||
@@ -1168,7 +1168,7 @@ Search for the old active-plan path and update any live links:
|
||||
rg -n "2026-07-23-atomic-workflow-output-bindings" docs skills README.md
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Run the complete focused matrix**
|
||||
- [x] **Step 5: Run the complete focused matrix**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -1204,7 +1204,7 @@ If the Windows `uv.exe` app alias is broken, use the repository environment:
|
||||
-q
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Run static verification**
|
||||
- [x] **Step 6: Run static verification**
|
||||
|
||||
Run:
|
||||
|
||||
@@ -1219,7 +1219,7 @@ Expected: all clean. Remove only verified workspace-local `.pytest-*` temporary
|
||||
directories before Ruff if an interrupted pytest run left generated fixture
|
||||
files under the repository root.
|
||||
|
||||
- [ ] **Step 7: Run independent whole-slice review**
|
||||
- [x] **Step 7: Run independent whole-slice review**
|
||||
|
||||
Review from the pre-plan implementation base through `HEAD` against
|
||||
`docs/superpowers/specs/2026-07-23-atomic-workflow-output-bindings-design.md`.
|
||||
@@ -1239,7 +1239,7 @@ the reviewer to inspect:
|
||||
Fix all Critical and Important findings, rerun affected tests/static checks, and
|
||||
repeat focused review until both Standards and Spec pass.
|
||||
|
||||
- [ ] **Step 8: Commit documentation and any final review fixes**
|
||||
- [x] **Step 8: Commit documentation and any final review fixes**
|
||||
|
||||
Commit the documentation/archive change:
|
||||
|
||||
+30
-18
@@ -320,7 +320,8 @@ wf draft set-name concat_ws --revision 1 --name concat_ws_v2
|
||||
wf draft set-route concat_ws --revision 2 --step call --outcome ok --to __end__
|
||||
wf draft set-input concat_ws --revision 3 --step call --map input.items=items --map input.separator=separator
|
||||
wf draft set-output concat_ws --revision 4 --step call --map value=state.value
|
||||
wf draft set-workflow-output concat_ws --revision 5 --map state.value=result
|
||||
wf draft set-workflow-output concat_ws --revision 5 \
|
||||
--map state.value=result --value format='"markdown"'
|
||||
wf draft set-input concat_ws --revision 6 --step call --merge --map input.limit=limit
|
||||
wf draft branch concat_ws --revision 7 --step call --route ok=__end__ --route error=tool_error
|
||||
wf draft handle concat_ws --revision 8 --to fail --branch lookup:error --branch transform:error
|
||||
@@ -363,22 +364,33 @@ repeated-source fan-out.
|
||||
`set-output` maps node-local output fields to workflow state paths:
|
||||
`text=state.text` means `local.text -> state.text`.
|
||||
|
||||
`set-workflow-output` maps graph source paths (`input.*`, `state.*`, or
|
||||
`context.*`) to top-level output fields: `state.value=result` means
|
||||
`state.value -> output.result`.
|
||||
`set-workflow-output` canonically replaces the complete ordered workflow-output
|
||||
binding list. Repeat `--map` for graph source paths (`input.*`, `state.*`, or
|
||||
`context.*`) and `--value` for literal JSON values. For example,
|
||||
`state.value=result` means `state.value -> output.result`, while
|
||||
`--value format='"markdown"'` writes a literal to `output.format`.
|
||||
|
||||
For single-field `input.*` and `state.*` sources, the command projects missing
|
||||
top-level `output_schema` fields from the source schema. More complex or
|
||||
undeclared paths still rely on `wf draft validate` diagnostics.
|
||||
Nested `input.*` and `state.*` source paths project missing nested
|
||||
`output_schema` fields from their declared source schemas. Literal bindings and
|
||||
`context.*` paths do not infer a schema: their output targets must already be
|
||||
declared, and literals must validate against those declared targets.
|
||||
|
||||
By default, `set-input` and `set-output` replace complete ordered canonical
|
||||
binding lists, while `set-workflow-output` replaces its complete map. Repeated
|
||||
`set-output --map LOCAL_SOURCE=STATE_TARGET` flags preserve their order and may
|
||||
repeat a source to fan it out to several state targets. Use
|
||||
`set-output --bindings-file` for an exported canonical list and `--clear` for an
|
||||
explicit empty replacement. Use `--merge --map` only for compatibility output
|
||||
map edits; that path cannot preserve canonical ordering or repeated-source
|
||||
fan-out.
|
||||
Use `--bindings-file` to restore an exported mixed path/value list without
|
||||
changing its order, or `--clear` to replace the list with `[]`. An empty
|
||||
workflow-output list restores the runtime's implicit same-name state fallback;
|
||||
it does not promise an always-empty public output. Use `--merge --map` only for
|
||||
the compatibility map adapter. It is intentionally lossy and cannot represent
|
||||
literals, canonical ordering, or repeated-source fan-out reliably.
|
||||
|
||||
```bash
|
||||
wf draft inspect WS --include-draft |
|
||||
jq '.draft.output' > output-bindings.json
|
||||
|
||||
wf draft set-workflow-output WS --revision 5 \
|
||||
--bindings-file output-bindings.json
|
||||
|
||||
wf draft set-workflow-output WS --revision 6 --clear
|
||||
```
|
||||
|
||||
### Bind A Step Path
|
||||
|
||||
@@ -413,10 +425,10 @@ Repair-hint examples:
|
||||
```bash
|
||||
# Declare an undeclared workflow input field and bind it to a step input
|
||||
wf draft bind report_ws --revision 4 --step read --from input.path --to local.path
|
||||
# Request a public workflow output; bind lowers it through state internally
|
||||
# Request a public workflow output through an explicit state projection
|
||||
wf draft bind report_ws --revision 5 --step render --from local.markdown --to output.markdown
|
||||
# Set workflow output independently (no schema projection)
|
||||
wf draft set-workflow-output report_ws --revision 6 --map state.markdown=markdown
|
||||
# Set workflow output independently, including a nested source projection
|
||||
wf draft set-workflow-output report_ws --revision 6 --map state.report.markdown=markdown
|
||||
```
|
||||
|
||||
The command combines two common edits:
|
||||
|
||||
@@ -155,10 +155,21 @@ Focused repair helpers:
|
||||
- `wf.workflow.set_step_output_bindings`
|
||||
- `wf.workflow.set_step_input_map`
|
||||
- `wf.workflow.set_step_output_map`
|
||||
- `wf.workflow.set_workflow_output_bindings`
|
||||
- `wf.workflow.set_workflow_output_map` (compatibility-only map adapter)
|
||||
|
||||
These helpers are deliberately narrow. Prefer them over JSON Patch when the
|
||||
caller only needs to edit one common field.
|
||||
|
||||
`wf.workflow.set_workflow_output_bindings` replaces the complete ordered
|
||||
top-level output projection. Its `bindings` list can mix graph paths and
|
||||
literal values. Nested `input.*` and `state.*` paths may project missing
|
||||
output-schema fields from declared source schemas; literal values and
|
||||
`context.*` paths require declared output targets. An empty list restores the
|
||||
implicit same-name state fallback. Use the map tool only for compatibility:
|
||||
`set_workflow_output_map` cannot preserve canonical path/value order, literals,
|
||||
or repeated-source fan-out.
|
||||
|
||||
Advanced workspace tools:
|
||||
|
||||
- `wf.workflow.list_draft_workspaces`: find mutable draft sessions.
|
||||
@@ -545,7 +556,7 @@ resending the full draft each turn.
|
||||
| Fetch current draft workspace | `wf.workflow.get_draft_workspace` |
|
||||
| Patch current draft workspace | `wf.workflow.patch_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_bindings`, `wf.workflow.set_step_output_bindings`, `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`, `wf.workflow.set_workflow_output_bindings` |
|
||||
| Save final workspace as artifact | `wf.workflow.create_artifact_from_workspace` |
|
||||
| Save final workspace as callable wrapper | `wf.workflow.create_wrapper_from_workspace` |
|
||||
| Clean up a draft workspace | `wf.workflow.delete_draft_workspace` |
|
||||
|
||||
@@ -313,7 +313,8 @@ For the copy-less wrapper authoring path, use:
|
||||
2. `wf.workflow.create_draft_workspace_from_capability` to create a patchable
|
||||
draft workspace from those hints.
|
||||
3. Focused patch helpers such as `wf.workflow.set_step_input_bindings`,
|
||||
`wf.workflow.set_step_output_bindings`, their compatibility map adapters,
|
||||
`wf.workflow.set_step_output_bindings`,
|
||||
`wf.workflow.set_workflow_output_bindings`, their compatibility map adapters,
|
||||
and `wf.workflow.set_draft_route` to fix low-confidence hints or explicit
|
||||
`missing_decisions`.
|
||||
4. `wf.workflow.validate_draft_workspace` to refresh diagnostics.
|
||||
|
||||
+27
-3
@@ -151,7 +151,16 @@ 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.
|
||||
projection is clearer for new workflows. Clearing canonical output bindings
|
||||
restores this fallback; it does not mean that the public output is always empty.
|
||||
|
||||
Canonical workflow-output replacement accepts an ordered union of path and
|
||||
literal bindings. Nested `input.*` and `state.*` sources can project missing
|
||||
nested output-schema fields from their declared source schemas. Literal values
|
||||
and `context.*` paths require an already-declared output target; literals are
|
||||
validated against that target and never used to infer a schema. Equal or
|
||||
ancestor/descendant output targets are rejected so the ordered list has one
|
||||
unambiguous public projection.
|
||||
|
||||
## Explicit Outputs And Error Outcomes
|
||||
|
||||
@@ -711,8 +720,13 @@ wf draft set-output <workspace_id> --revision <n> --step <step_id> --map text=st
|
||||
wf draft set-output <workspace_id> --revision <n> --step <step_id> --bindings-file output-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-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> \
|
||||
--map state.value=result --value format='"markdown"'
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> \
|
||||
--bindings-file output-bindings.json
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> --clear
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> \
|
||||
--merge --map state.other=other
|
||||
wf draft branch <workspace_id> --revision <n> --step <step_id> --route ok=__end__ --route error=tool_error
|
||||
wf draft handle <workspace_id> --revision <n> --to fail --branch lookup:error --branch transform:error
|
||||
wf draft compile <workspace_id>
|
||||
@@ -726,6 +740,16 @@ empty replacement. The legacy `--merge --map` path is compatibility-only and
|
||||
potentially lossy because a map cannot preserve ordering or repeated-source
|
||||
fan-out.
|
||||
|
||||
`set-workflow-output` follows the same canonical replacement model for the
|
||||
top-level `WorkflowDraft.output` list. Use repeated `--map` and `--value`
|
||||
flags for a small ordered edit, or `--bindings-file` for an exact round trip
|
||||
from `draft inspect --include-draft`. `--clear` writes an empty list and
|
||||
restores the implicit same-name state fallback. Literal and `context.*`
|
||||
bindings need declared output targets; nested `input.*` and `state.*` paths
|
||||
may project their declared source schema into missing nested output fields.
|
||||
The compatibility `--merge --map` form remains available only for lossy map
|
||||
edits and cannot preserve literals, order, or repeated-source fan-out.
|
||||
|
||||
Use `draft patch` when these focused commands do not cover the structural edit.
|
||||
|
||||
Drafts are not raw workflow plans. Drafts use `steps`, `routes`, and step field
|
||||
|
||||
+18
-6
@@ -51,8 +51,13 @@ wf draft set-output <workspace_id> --revision <n> --step <step_id> --map text=st
|
||||
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-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> \
|
||||
--map state.value=result --value format='"markdown"'
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> \
|
||||
--bindings-file output-bindings.json
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> --clear
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> \
|
||||
--merge --map state.other=other
|
||||
wf draft branch <workspace_id> --revision <n> --step <step_id> --route ok=__end__ --route error=fail
|
||||
wf draft handle <workspace_id> --revision <n> --to fail --branch lookup:error --branch transform:error
|
||||
wf draft compile <workspace_id>
|
||||
@@ -90,10 +95,12 @@ compatibility map-only edit when the workflow schema is already declared.
|
||||
local side, so their targets are rootless paths: write
|
||||
`input.title=report.title`, not `input.title=local.report.title`.
|
||||
|
||||
`wf draft set-workflow-output` projects missing public output schema fields for
|
||||
single-field `input.*` and `state.*` sources. Prefer it for final workflow
|
||||
outputs; use `wf draft bind --from local.x --to output.y` when the source is a
|
||||
step-local capability output.
|
||||
`wf draft set-workflow-output` replaces the complete ordered public output
|
||||
projection. Nested `input.*` and `state.*` sources can project missing nested
|
||||
output-schema fields from declared source schemas. Literal values and
|
||||
`context.*` paths require declared output targets; literals validate against
|
||||
those targets and do not infer schemas. Use `wf draft bind --from local.x --to
|
||||
output.y` when the source is a step-local capability output.
|
||||
|
||||
When `wf draft validate` returns a `repair_hint`, run that exact focused command
|
||||
before writing JSON Patch manually. To make one capability output public, use
|
||||
@@ -171,6 +178,11 @@ 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.
|
||||
|
||||
Use `set-workflow-output` without `--merge` when replacing the complete public
|
||||
output projection. Use `--bindings-file` when exact path/value interleaving
|
||||
must round-trip, and `--clear` to restore implicit same-name state fallback.
|
||||
Use `--merge --map` only when a lossy compatibility edit is acceptable.
|
||||
|
||||
Prefer `draft bind` when a capability step binding also needs schema
|
||||
projection. Use `input/state -> local` for step inputs and `local ->
|
||||
state/output` for step outputs. It requires a capability-backed step with
|
||||
|
||||
@@ -87,7 +87,8 @@ Prefer focused helpers over JSON Patch for common edits:
|
||||
- `set_step_input_map`
|
||||
- `set_step_output_bindings`
|
||||
- `set_step_output_map`
|
||||
- `set_workflow_output_map`
|
||||
- `set_workflow_output_bindings`
|
||||
- `set_workflow_output_map` (compatibility-only map adapter)
|
||||
- `bind_draft`
|
||||
- `add_step`
|
||||
- `add_step_from_capability`
|
||||
@@ -109,8 +110,13 @@ wf draft set-output <workspace_id> --revision <n> --step <step_id> --map text=st
|
||||
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-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> \
|
||||
--map state.value=result --value format='"markdown"'
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> \
|
||||
--bindings-file output-bindings.json
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> --clear
|
||||
wf draft set-workflow-output <workspace_id> --revision <n> \
|
||||
--merge --map state.other=other
|
||||
wf draft branch <workspace_id> --revision <n> --step <step_id> --route ok=__end__ --route error=fail
|
||||
wf draft handle <workspace_id> --revision <n> --to fail --branch lookup:error --branch transform:error
|
||||
wf draft compile <workspace_id>
|
||||
@@ -121,11 +127,13 @@ wf draft add interrupt <workspace_id> --revision <n> --step review --kind issue_
|
||||
wf draft add when <workspace_id> --revision <n> --step decide --condition-file condition.json --then next --otherwise revise
|
||||
```
|
||||
|
||||
`set-workflow-output` maps a graph source path (`input.*`, `state.*`, or
|
||||
`context.*`) to one public workflow output field. It edits top-level
|
||||
`WorkflowDraft.output`; `set-output` edits one step's local-to-state bindings.
|
||||
For single-field `input.*` and `state.*` sources, missing public output schema
|
||||
fields are projected automatically from the source schema.
|
||||
`set-workflow-output` replaces the complete ordered top-level
|
||||
`WorkflowDraft.output` binding list. It accepts graph source paths
|
||||
(`input.*`, `state.*`, or `context.*`) and literal values; `set-output` edits
|
||||
one step's local-to-state bindings. Nested `input.*` and `state.*` sources can
|
||||
project missing output-schema fields from their declared source schemas.
|
||||
Literal values and `context.*` paths require declared output targets, and
|
||||
literal values are validated against those targets rather than inferred.
|
||||
|
||||
`set-input` direction: `input.title=report.title` means graph source
|
||||
`input.title` maps to node-local target `local.report.title`. Targets are
|
||||
@@ -178,9 +186,10 @@ wf draft set-output WS --revision 5 --step analyze \
|
||||
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.
|
||||
`--clear` replaces the list with `[]` and restores the implicit same-name state
|
||||
fallback. `--merge --map` is compatibility-only and may collapse existing
|
||||
fan-out; it cannot preserve literals or canonical ordering. Use it only when a
|
||||
lossy map edit is acceptable.
|
||||
|
||||
`bind input.title -> local.report.title` is schema-aware and idempotent when
|
||||
`input.title` is already declared. Bind names both rooted endpoints explicitly.
|
||||
|
||||
@@ -16,10 +16,15 @@ validated, runnable deployment.
|
||||
5. Inspect/patch/validate the workspace until valid.
|
||||
- Use focused CLI commands (`set-name`, `set-route`, `set-input`, `set-output`)
|
||||
for common edits.
|
||||
- `set-input` and `set-output` replace their ordered canonical binding lists.
|
||||
- `set-input`, `set-output`, and `set-workflow-output` replace their ordered
|
||||
canonical binding lists.
|
||||
Repeated sources preserve fan-out to distinct targets. The `--merge`
|
||||
variants are compatibility-only and cannot preserve canonical ordering or
|
||||
repeated-source fan-out; existing literals are retained for input merges.
|
||||
- `set-workflow-output` accepts ordered path/value bindings. Nested
|
||||
`input.*` and `state.*` sources can project declared source schemas into
|
||||
missing output fields; literals and `context.*` require declared targets.
|
||||
`--clear` restores implicit same-name state fallback.
|
||||
- Before mapping into a new workflow input, state, or output field, prefer
|
||||
`wf draft bind --from ... --to ...` when it should mirror a capability
|
||||
local input/output property. It declares the matching schema and merges
|
||||
|
||||
Reference in New Issue
Block a user