@@ -23,6 +23,8 @@ repositories:
2323| Update workflow | ` tests/fixtures/control-plane/workflow-update-parity.json ` |
2424| Cancel workflow | ` tests/fixtures/control-plane/workflow-cancel-parity.json ` |
2525| Workflow task history page | ` tests/fixtures/control-plane/workflow-task-history-parity.json ` |
26+ | Set namespace external storage driver | ` tests/fixtures/control-plane/namespace-set-storage-driver-parity.json ` |
27+ | Storage round-trip diagnostic | ` tests/fixtures/control-plane/storage-test-parity.json ` |
2628
2729The CLI sends JSON caller payloads directly. The Python SDK wraps the same
2830semantic payload in its Avro envelope. Both target the same endpoint and
@@ -231,6 +233,87 @@ JSON request body. Both surfaces preserve the canonical server response fields:
231233Do not treat the control-plane aliases ` events ` or ` next_page_token ` as valid
232234worker-history response fields.
233235
236+ ## Set Namespace External Storage Driver
237+
238+ Configure the external payload storage policy that the server applies when an
239+ encoded workflow payload exceeds the namespace threshold. The CLI and Python
240+ SDK drive the same namespace-scoped control-plane endpoint.
241+
242+ CLI:
243+
244+ ``` bash
245+ dw namespace:set-storage-driver billing s3 \
246+ --threshold-bytes=2097152 \
247+ --bucket=dw-payloads \
248+ --prefix=billing/ \
249+ --region=us-east-1 \
250+ --endpoint=https://s3.us-east-1.amazonaws.com \
251+ --auth-profile=billing-prod \
252+ --json
253+ ```
254+
255+ Python:
256+
257+ ``` python
258+ async with client:
259+ namespace = await client.set_namespace_external_storage(
260+ " billing" ,
261+ driver = " s3" ,
262+ enabled = True ,
263+ threshold_bytes = 2_097_152 ,
264+ config = {
265+ " bucket" : " dw-payloads" ,
266+ " prefix" : " billing/" ,
267+ " region" : " us-east-1" ,
268+ " endpoint" : " https://s3.us-east-1.amazonaws.com" ,
269+ " auth_profile" : " billing-prod" ,
270+ },
271+ )
272+ ```
273+
274+ Both calls mean ` PUT /namespaces/{name}/external-storage ` . The response is the
275+ refreshed namespace description, and its ` external_payload_storage ` envelope
276+ carries the same ` driver ` , ` enabled ` , ` threshold_bytes ` , and ` config ` fields
277+ both surfaces sent. Use ` --disable ` on the CLI or ` enabled=False ` from Python
278+ to retain the policy record while switching the driver off.
279+
280+ ## Storage Round-Trip Diagnostic
281+
282+ Ask the server to round-trip a small inline payload and an over-threshold
283+ payload through the namespace's configured external storage. This is the
284+ operator check that proves a driver is wired up end-to-end before running real
285+ workflow traffic through it.
286+
287+ CLI:
288+
289+ ``` bash
290+ dw storage:test \
291+ --driver=s3 \
292+ --small-bytes=128 \
293+ --large-bytes=3145728 \
294+ --json
295+ ```
296+
297+ Python:
298+
299+ ``` python
300+ async with client:
301+ result = await client.test_external_storage(
302+ driver = " s3" ,
303+ small_payload_bytes = 128 ,
304+ large_payload_bytes = 3_145_728 ,
305+ )
306+ ```
307+
308+ Both calls mean ` POST /storage/test ` . The CLI reads the active namespace from
309+ ` --namespace ` or ` DURABLE_WORKFLOW_NAMESPACE ` ; the Python SDK reads it from the
310+ ` Client(namespace=...) ` constructor. Both surfaces return the same response
311+ envelope: top-level ` status ` , ` driver ` , and per-payload ` small_payload ` /
312+ ` large_payload ` blocks that carry ` status ` , ` bytes ` , ` sha256 ` , and (for the
313+ over-threshold payload) the ` reference_uri ` the server would embed in workflow
314+ history. Omit ` driver ` to exercise the currently configured namespace policy
315+ instead of overriding it for the diagnostic.
316+
234317## Parity Checklist
235318
236319When adding a new CLI or SDK operation, keep the contract language-neutral:
0 commit comments