docs: complete safe draft transfer

This commit is contained in:
lda
2026-07-29 09:56:12 +07:00 Verified
parent c1d81bf6f5
commit 1d2acc50e8
6 changed files with 62 additions and 31 deletions
+8
View File
@@ -600,6 +600,14 @@ clear operator feedback before adding more architecture.
fallback; compatibility `--merge --map` remains intentionally lossy. fallback; compatibility `--merge --map` remains intentionally lossy.
Implementation: Implementation:
[`atomic workflow output bindings`](historical/superpowers/plans/2026-07-23-atomic-workflow-output-bindings.md). [`atomic workflow output bindings`](historical/superpowers/plans/2026-07-23-atomic-workflow-output-bindings.md).
- Completed: compatibility map merges now reject canonical input/output
bindings they cannot preserve, and local or remote CLI users can export an
exact draft document and revision-check its import into an existing
workspace. Structurally valid imports receive fresh semantic diagnostics and
remain repairable when invalid. Implementation:
[`safe compatibility merges`](historical/superpowers/plans/2026-07-29-safe-compatibility-merges.md)
and
[`draft document transfer`](historical/superpowers/plans/2026-07-29-draft-document-transfer.md).
- Completed: challenge-driven output UX polish makes `set-workflow-output` - Completed: challenge-driven output UX polish makes `set-workflow-output`
project missing top-level output schema fields from declared `input.*` and project missing top-level output schema fields from declared `input.*` and
`state.*` sources, and challenge prompt templates now always include `state.*` sources, and challenge prompt templates now always include
@@ -1,5 +1,7 @@
# Draft Document Transfer Implementation Plan # Draft Document Transfer Implementation Plan
**Status:** Completed
> **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 (`- [ ]`) syntax for tracking.
**Goal:** Export exact draft documents and import them into existing revisioned workspaces through local or remote CLI. **Goal:** Export exact draft documents and import them into existing revisioned workspaces through local or remote CLI.
@@ -39,7 +41,7 @@
- Produces: `WorkflowApi.replace_draft_workspace_document` - Produces: `WorkflowApi.replace_draft_workspace_document`
- Produces: `WorkflowDraftSurface.replace_draft_workspace_document` - Produces: `WorkflowDraftSurface.replace_draft_workspace_document`
- [ ] **Step 1: Write failing artifact-layer tests** - [x] **Step 1: Write failing artifact-layer tests**
Add tests proving: Add tests proving:
@@ -63,7 +65,7 @@ Also add tests for:
- semantically invalid routes are persisted at revision 2 with - semantically invalid routes are persisted at revision 2 with
`status == "invalid"` and fresh diagnostics. `status == "invalid"` and fresh diagnostics.
- [ ] **Step 2: Run artifact tests and verify RED** - [x] **Step 2: Run artifact tests and verify RED**
Run: Run:
@@ -73,7 +75,7 @@ uv run pytest tests/artifacts/test_draft_workspaces.py -k "replace_draft_workspa
Expected: collection fails because the operation is not defined. Expected: collection fails because the operation is not defined.
- [ ] **Step 3: Implement the artifact operation** - [x] **Step 3: Implement the artifact operation**
Add: Add:
@@ -104,7 +106,7 @@ Implementation order:
Export the function through both artifact package `__init__.py` files. Export the function through both artifact package `__init__.py` files.
- [ ] **Step 4: Write and run API façade tests** - [x] **Step 4: Write and run API façade tests**
In `tests/wf_api/test_drafts_service.py`, add one test that registers a In `tests/wf_api/test_drafts_service.py`, add one test that registers a
capability, imports a draft using it, and asserts current capability definitions capability, imports a draft using it, and asserts current capability definitions
@@ -119,7 +121,7 @@ uv run pytest tests/wf_api/test_drafts_service.py -k "replace_draft_workspace_do
Expected before façade implementation: FAIL with missing method. Expected before façade implementation: FAIL with missing method.
- [ ] **Step 5: Thread the operation through API and surface** - [x] **Step 5: Thread the operation through API and surface**
Add this signature to `WorkflowDraftApi`, `WorkflowApi`, and Add this signature to `WorkflowDraftApi`, `WorkflowApi`, and
`WorkflowDraftSurface`: `WorkflowDraftSurface`:
@@ -138,7 +140,7 @@ async def replace_draft_workspace_document(
`node_defs_for_draft=self._node_defs_for_draft`. `WorkflowApi` delegates to `node_defs_for_draft=self._node_defs_for_draft`. `WorkflowApi` delegates to
`self.drafts`. `self.drafts`.
- [ ] **Step 6: Run focused tests and commit** - [x] **Step 6: Run focused tests and commit**
Run: Run:
@@ -170,7 +172,7 @@ git commit -m "feat: replace complete draft documents safely"
- Produces RPC method: `workflow.draft_workspaces.replace_document` - Produces RPC method: `workflow.draft_workspaces.replace_document`
- Produces client method: `RpcDraftClientMixin.replace_draft_workspace_document` - Produces client method: `RpcDraftClientMixin.replace_draft_workspace_document`
- [ ] **Step 1: Write failing RPC application test** - [x] **Step 1: Write failing RPC application test**
Create a workspace, then call: Create a workspace, then call:
@@ -191,7 +193,7 @@ Inspect the workspace with `include_draft=True` and assert exact imported
content. Add a malformed `draft=[]` request test that expects JSON-RPC parameter content. Add a malformed `draft=[]` request test that expects JSON-RPC parameter
validation failure without mutation. validation failure without mutation.
- [ ] **Step 2: Run RPC application tests and verify RED** - [x] **Step 2: Run RPC application tests and verify RED**
Run: Run:
@@ -201,7 +203,7 @@ uv run pytest tests/wf_transport_rpc_http/test_app.py -k "replace_document" -q
Expected: method-not-found failure. Expected: method-not-found failure.
- [ ] **Step 3: Add the request model and RPC method** - [x] **Step 3: Add the request model and RPC method**
Add: Add:
@@ -217,7 +219,7 @@ Export it from `wf_transport_rpc_http.__init__`. Register
to `server.api.replace_draft_workspace_document` and using the existing to `server.api.replace_draft_workspace_document` and using the existing
`WorkflowRpcError` translation. `WorkflowRpcError` translation.
- [ ] **Step 4: Write failing client request test** - [x] **Step 4: Write failing client request test**
In `test_client.py`, assert: In `test_client.py`, assert:
@@ -237,13 +239,13 @@ assert calls[-1] == {
} }
``` ```
- [ ] **Step 5: Implement the remote client method** - [x] **Step 5: Implement the remote client method**
Add the exact `WorkflowDraftSurface` signature to `RpcDraftClientMixin` and Add the exact `WorkflowDraftSurface` signature to `RpcDraftClientMixin` and
delegate through `_call("workflow.draft_workspaces.replace_document", params)`. delegate through `_call("workflow.draft_workspaces.replace_document", params)`.
Do not normalize or lower the draft through another model in the client. Do not normalize or lower the draft through another model in the client.
- [ ] **Step 6: Run transport tests and commit** - [x] **Step 6: Run transport tests and commit**
Run: Run:
@@ -272,7 +274,7 @@ git commit -m "feat: expose draft document replacement over rpc"
- Produces: `write_json_file(path, payload, *, force)` - Produces: `write_json_file(path, payload, *, force)`
- Produces CLI command: `wf draft export WORKSPACE --output PATH [--force]` - Produces CLI command: `wf draft export WORKSPACE --output PATH [--force]`
- [ ] **Step 1: Write failing local export tests** - [x] **Step 1: Write failing local export tests**
Using a fake handler whose `get_draft_workspace` returns: Using a fake handler whose `get_draft_workspace` returns:
@@ -290,7 +292,7 @@ Assert:
- `--force` replaces it; - `--force` replaces it;
- a missing parent reports a CLI error. - a missing parent reports a CLI error.
- [ ] **Step 2: Run export tests and verify RED** - [x] **Step 2: Run export tests and verify RED**
Run: Run:
@@ -300,7 +302,7 @@ uv run pytest tests/wf_cli/test_app.py -k "draft_export" -q
Expected: command-not-found failure. Expected: command-not-found failure.
- [ ] **Step 3: Add the file writer and command** - [x] **Step 3: Add the file writer and command**
In `wf_cli.io`, add: In `wf_cli.io`, add:
@@ -342,13 +344,13 @@ def export_draft(
Fetch with `include_draft=True`, require `payload["draft"]` to be a dictionary, Fetch with `include_draft=True`, require `payload["draft"]` to be a dictionary,
and call `write_json_file`. Do not call `emit_json`. and call `write_json_file`. Do not call `emit_json`.
- [ ] **Step 4: Add remote-target export test** - [x] **Step 4: Add remote-target export test**
Use the existing remote target fixture and assert the RPC request is Use the existing remote target fixture and assert the RPC request is
`workflow.draft_workspaces.get` with `include_draft: true`. Assert the resulting `workflow.draft_workspaces.get` with `include_draft: true`. Assert the resulting
file contains only the draft, not workspace metadata. file contains only the draft, not workspace metadata.
- [ ] **Step 5: Run CLI tests and commit** - [x] **Step 5: Run CLI tests and commit**
Run: Run:
@@ -377,7 +379,7 @@ git commit -m "feat: export draft documents"
- Consumes: `WorkflowDraftSurface.replace_draft_workspace_document` - Consumes: `WorkflowDraftSurface.replace_draft_workspace_document`
- Produces CLI command: `wf draft import WORKSPACE --revision N --file PATH` - Produces CLI command: `wf draft import WORKSPACE --revision N --file PATH`
- [ ] **Step 1: Write failing local import tests** - [x] **Step 1: Write failing local import tests**
Assert the command: Assert the command:
@@ -398,7 +400,7 @@ replace_draft_workspace_document(
Add CLI-input tests for missing files, malformed JSON, and JSON arrays. Assert Add CLI-input tests for missing files, malformed JSON, and JSON arrays. Assert
these fail before `load_cli_context` is called. these fail before `load_cli_context` is called.
- [ ] **Step 2: Run import tests and verify RED** - [x] **Step 2: Run import tests and verify RED**
Run: Run:
@@ -408,7 +410,7 @@ uv run pytest tests/wf_cli/test_app.py -k "draft_import" -q
Expected: command-not-found failure. Expected: command-not-found failure.
- [ ] **Step 3: Implement the import command** - [x] **Step 3: Implement the import command**
Add: Add:
@@ -449,7 +451,7 @@ emit_json(
) )
``` ```
- [ ] **Step 4: Add remote import and round-trip tests** - [x] **Step 4: Add remote import and round-trip tests**
Add a remote-target test asserting method Add a remote-target test asserting method
`workflow.draft_workspaces.replace_document` and exact draft payload. `workflow.draft_workspaces.replace_document` and exact draft payload.
@@ -462,7 +464,7 @@ Add one round-trip test:
4. assert destination `draft` equals the exported object; 4. assert destination `draft` equals the exported object;
5. assert destination workspace ID remains unchanged. 5. assert destination workspace ID remains unchanged.
- [ ] **Step 5: Run CLI tests and commit** - [x] **Step 5: Run CLI tests and commit**
Run: Run:
@@ -485,12 +487,12 @@ git commit -m "feat: import draft documents"
- Modify: `skills/wf-cli/SKILL.md` - Modify: `skills/wf-cli/SKILL.md`
- Modify: `docs/current_roadmap.md` - Modify: `docs/current_roadmap.md`
- Reference: `docs/historical/superpowers/plans/2026-07-29-safe-compatibility-merges.md` - Reference: `docs/historical/superpowers/plans/2026-07-29-safe-compatibility-merges.md`
- Move: `docs/superpowers/plans/2026-07-29-draft-document-transfer.md` - Archive: `docs/historical/superpowers/plans/2026-07-29-draft-document-transfer.md`
**Interfaces:** **Interfaces:**
- Documents: safe map merge, export, and revision-checked import - Documents: safe map merge, export, and revision-checked import
- [ ] **Step 1: Update CLI skill examples** - [x] **Step 1: Update CLI skill examples**
Add a concise transfer sequence: Add a concise transfer sequence:
@@ -504,7 +506,7 @@ State that exported files contain only the draft document and that import
targets an already existing workspace. State that semantic-invalid imports are targets an already existing workspace. State that semantic-invalid imports are
stored with diagnostics for repair. stored with diagnostics for repair.
- [ ] **Step 2: Update roadmap and archive completed plans** - [x] **Step 2: Update roadmap and archive completed plans**
Add one completed roadmap item linking to both historical plan paths. The safe Add one completed roadmap item linking to both historical plan paths. The safe
compatibility plan is already archived; move the draft-transfer plan under: compatibility plan is already archived; move the draft-transfer plan under:
@@ -519,7 +521,7 @@ Update any references found by:
rg -n "2026-07-29-(safe-compatibility-merges|draft-document-transfer)" docs skills rg -n "2026-07-29-(safe-compatibility-merges|draft-document-transfer)" docs skills
``` ```
- [ ] **Step 3: Run focused and static verification** - [x] **Step 3: Run focused and static verification**
Run: Run:
@@ -534,13 +536,13 @@ git diff --check
Expected: all tests pass, formatting is unchanged, Ruff reports no issues, Expected: all tests pass, formatting is unchanged, Ruff reports no issues,
basedpyright reports zero errors, and diff check is clean. basedpyright reports zero errors, and diff check is clean.
- [ ] **Step 4: Review the combined implementation** - [x] **Step 4: Review the combined implementation**
Invoke the repository code-review workflow against the pre-slice commit. Fix Invoke the repository code-review workflow against the pre-slice commit. Fix
Critical and Important findings, rerun the affected focused tests, and record Critical and Important findings, rerun the affected focused tests, and record
any intentionally deferred Minor findings in the final report. any intentionally deferred Minor findings in the final report.
- [ ] **Step 5: Commit documentation and plan archival** - [x] **Step 5: Commit documentation and plan archival**
```bash ```bash
git add skills/wf-cli/SKILL.md docs/current_roadmap.md docs/superpowers/plans docs/historical/superpowers/plans git add skills/wf-cli/SKILL.md docs/current_roadmap.md docs/superpowers/plans docs/historical/superpowers/plans
+16
View File
@@ -37,6 +37,8 @@ wf cap call <capability> --input '{"field":"value"}'
wf draft create <workspace_id> --name <name> wf draft create <workspace_id> --name <name>
wf draft create <workspace_id> --capability <capability> wf draft create <workspace_id> --capability <capability>
wf draft inspect <workspace_id> --include-draft wf draft inspect <workspace_id> --include-draft
wf draft export <workspace_id> --output draft.json
wf draft import <workspace_id> --revision <n> --file draft.json
wf draft patch <workspace_id> --revision <n> --input-file patch.json wf draft patch <workspace_id> --revision <n> --input-file patch.json
wf draft set-name <workspace_id> --revision <n> --name <name> wf draft set-name <workspace_id> --revision <n> --name <name>
wf draft set-start <workspace_id> --revision <n> --step <step_id> wf draft set-start <workspace_id> --revision <n> --step <step_id>
@@ -217,6 +219,20 @@ after the intended steps and routes are present.
`wf draft compile` prints the raw plan JSON directly on success. Do not expect a `wf draft compile` prints the raw plan JSON directly on success. Do not expect a
top-level `compiled_plan` key from the CLI output. top-level `compiled_plan` key from the CLI output.
Transfer an exact draft document between existing workspaces with:
```bash
uv run wf draft export report --output report-draft.json
uv run wf draft import restored --revision 1 --file report-draft.json
uv run wf draft validate restored
```
The export file contains only the draft document, not workspace ID, revision,
status, or diagnostics. Import requires an existing destination workspace and
its expected revision; it replaces the destination draft without renaming the
workspace. A structurally valid but semantically invalid import is stored with
fresh diagnostics so it can be repaired in place.
- To undo a bad draft edit, prefer `wf draft remove-route`, - To undo a bad draft edit, prefer `wf draft remove-route`,
`wf draft remove-step`, or `wf draft remove-binding` over JSON Patch. `wf draft remove-step`, or `wf draft remove-binding` over JSON Patch.
+6 -1
View File
@@ -111,7 +111,12 @@ def replace_draft_workspace_document(
draft: JsonObject, draft: JsonObject,
node_defs_for_draft: NodeDefsForDraft, node_defs_for_draft: NodeDefsForDraft,
) -> JsonObject: ) -> JsonObject:
"""Replace and semantically revalidate one complete draft document.""" """Replace one complete draft under optimistic revision control.
Structural validation happens before mutation. Semantically invalid
documents remain byte-shape-equivalent and are stored with fresh diagnostics
for repair, while valid documents are canonicalized before persistence.
"""
workspace = store.get_workspace(workspace_id) workspace = store.get_workspace(workspace_id)
if workspace.revision != revision: if workspace.revision != revision:
return _revision_conflict_payload(workspace, revision) return _revision_conflict_payload(workspace, revision)
+1 -1
View File
@@ -34,10 +34,10 @@ from .models import (
PatchDraftParams, PatchDraftParams,
PatchDraftWorkspaceParams, PatchDraftWorkspaceParams,
ReadRunTraceParams, ReadRunTraceParams,
ReplaceDraftWorkspaceDocumentParams,
RemoveDraftBindingParams, RemoveDraftBindingParams,
RemoveDraftRouteParams, RemoveDraftRouteParams,
RemoveDraftStepParams, RemoveDraftStepParams,
ReplaceDraftWorkspaceDocumentParams,
ResumeRunParams, ResumeRunParams,
RouteSourceParams, RouteSourceParams,
SaveArtifactParams, SaveArtifactParams,
+1 -1
View File
@@ -24,10 +24,10 @@ from ..models import (
ListDraftWorkspacesParams, ListDraftWorkspacesParams,
PatchDraftParams, PatchDraftParams,
PatchDraftWorkspaceParams, PatchDraftWorkspaceParams,
ReplaceDraftWorkspaceDocumentParams,
RemoveDraftBindingParams, RemoveDraftBindingParams,
RemoveDraftRouteParams, RemoveDraftRouteParams,
RemoveDraftStepParams, RemoveDraftStepParams,
ReplaceDraftWorkspaceDocumentParams,
SetDraftContractParams, SetDraftContractParams,
SetDraftNameParams, SetDraftNameParams,
SetDraftRouteParams, SetDraftRouteParams,