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.
Implementation:
[`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`
project missing top-level output schema fields from declared `input.*` and
`state.*` sources, and challenge prompt templates now always include
@@ -1,5 +1,7 @@
# 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.
**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: `WorkflowDraftSurface.replace_draft_workspace_document`
- [ ] **Step 1: Write failing artifact-layer tests**
- [x] **Step 1: Write failing artifact-layer tests**
Add tests proving:
@@ -63,7 +65,7 @@ Also add tests for:
- semantically invalid routes are persisted at revision 2 with
`status == "invalid"` and fresh diagnostics.
- [ ] **Step 2: Run artifact tests and verify RED**
- [x] **Step 2: Run artifact tests and verify RED**
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.
- [ ] **Step 3: Implement the artifact operation**
- [x] **Step 3: Implement the artifact operation**
Add:
@@ -104,7 +106,7 @@ Implementation order:
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
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.
- [ ] **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
`WorkflowDraftSurface`:
@@ -138,7 +140,7 @@ async def replace_draft_workspace_document(
`node_defs_for_draft=self._node_defs_for_draft`. `WorkflowApi` delegates to
`self.drafts`.
- [ ] **Step 6: Run focused tests and commit**
- [x] **Step 6: Run focused tests and commit**
Run:
@@ -170,7 +172,7 @@ git commit -m "feat: replace complete draft documents safely"
- Produces RPC method: `workflow.draft_workspaces.replace_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:
@@ -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
validation failure without mutation.
- [ ] **Step 2: Run RPC application tests and verify RED**
- [x] **Step 2: Run RPC application tests and verify RED**
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.
- [ ] **Step 3: Add the request model and RPC method**
- [x] **Step 3: Add the request model and RPC method**
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
`WorkflowRpcError` translation.
- [ ] **Step 4: Write failing client request test**
- [x] **Step 4: Write failing client request test**
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
delegate through `_call("workflow.draft_workspaces.replace_document", params)`.
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:
@@ -272,7 +274,7 @@ git commit -m "feat: expose draft document replacement over rpc"
- Produces: `write_json_file(path, payload, *, 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:
@@ -290,7 +292,7 @@ Assert:
- `--force` replaces it;
- 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:
@@ -300,7 +302,7 @@ uv run pytest tests/wf_cli/test_app.py -k "draft_export" -q
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:
@@ -342,13 +344,13 @@ def export_draft(
Fetch with `include_draft=True`, require `payload["draft"]` to be a dictionary,
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
`workflow.draft_workspaces.get` with `include_draft: true`. Assert the resulting
file contains only the draft, not workspace metadata.
- [ ] **Step 5: Run CLI tests and commit**
- [x] **Step 5: Run CLI tests and commit**
Run:
@@ -377,7 +379,7 @@ git commit -m "feat: export draft documents"
- Consumes: `WorkflowDraftSurface.replace_draft_workspace_document`
- 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:
@@ -398,7 +400,7 @@ replace_draft_workspace_document(
Add CLI-input tests for missing files, malformed JSON, and JSON arrays. Assert
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:
@@ -408,7 +410,7 @@ uv run pytest tests/wf_cli/test_app.py -k "draft_import" -q
Expected: command-not-found failure.
- [ ] **Step 3: Implement the import command**
- [x] **Step 3: Implement the import command**
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
`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;
5. assert destination workspace ID remains unchanged.
- [ ] **Step 5: Run CLI tests and commit**
- [x] **Step 5: Run CLI tests and commit**
Run:
@@ -485,12 +487,12 @@ git commit -m "feat: import draft documents"
- Modify: `skills/wf-cli/SKILL.md`
- Modify: `docs/current_roadmap.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:**
- 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:
@@ -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
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
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
```
- [ ] **Step 3: Run focused and static verification**
- [x] **Step 3: Run focused and static verification**
Run:
@@ -534,13 +536,13 @@ git diff --check
Expected: all tests pass, formatting is unchanged, Ruff reports no issues,
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
Critical and Important findings, rerun the affected focused tests, and record
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
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> --capability <capability>
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 set-name <workspace_id> --revision <n> --name <name>
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
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`,
`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,
node_defs_for_draft: NodeDefsForDraft,
) -> 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)
if workspace.revision != revision:
return _revision_conflict_payload(workspace, revision)
+1 -1
View File
@@ -34,10 +34,10 @@ from .models import (
PatchDraftParams,
PatchDraftWorkspaceParams,
ReadRunTraceParams,
ReplaceDraftWorkspaceDocumentParams,
RemoveDraftBindingParams,
RemoveDraftRouteParams,
RemoveDraftStepParams,
ReplaceDraftWorkspaceDocumentParams,
ResumeRunParams,
RouteSourceParams,
SaveArtifactParams,
+1 -1
View File
@@ -24,10 +24,10 @@ from ..models import (
ListDraftWorkspacesParams,
PatchDraftParams,
PatchDraftWorkspaceParams,
ReplaceDraftWorkspaceDocumentParams,
RemoveDraftBindingParams,
RemoveDraftRouteParams,
RemoveDraftStepParams,
ReplaceDraftWorkspaceDocumentParams,
SetDraftContractParams,
SetDraftNameParams,
SetDraftRouteParams,