@temporal-architect/claude-plugin 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/package.json +37 -0
  4. package/skills/MANIFEST.json +373 -0
  5. package/skills/MANIFEST.md +121 -0
  6. package/skills/temporal-architect/SKILL.md +99 -0
  7. package/skills/temporal-architect/reference/decomposition.md +78 -0
  8. package/skills/temporal-architect-author-go/README.md +16 -0
  9. package/skills/temporal-architect-author-go/SKILL.md +191 -0
  10. package/skills/temporal-architect-author-go/SUBAGENT_ADOPTION.md +161 -0
  11. package/skills/temporal-architect-author-go/reference/activity-call.md +73 -0
  12. package/skills/temporal-architect-author-go/reference/activity-def.md +54 -0
  13. package/skills/temporal-architect-author-go/reference/assignment.md +36 -0
  14. package/skills/temporal-architect-author-go/reference/await-all.md +104 -0
  15. package/skills/temporal-architect-author-go/reference/await-one.md +193 -0
  16. package/skills/temporal-architect-author-go/reference/await-timer.md +35 -0
  17. package/skills/temporal-architect-author-go/reference/close.md +71 -0
  18. package/skills/temporal-architect-author-go/reference/composite-patterns.md +176 -0
  19. package/skills/temporal-architect-author-go/reference/condition.md +56 -0
  20. package/skills/temporal-architect-author-go/reference/control-flow.md +151 -0
  21. package/skills/temporal-architect-author-go/reference/dependency-resolution.md +29 -0
  22. package/skills/temporal-architect-author-go/reference/detach.md +52 -0
  23. package/skills/temporal-architect-author-go/reference/heartbeat.md +84 -0
  24. package/skills/temporal-architect-author-go/reference/nexus-service-def.md +73 -0
  25. package/skills/temporal-architect-author-go/reference/nexus.md +35 -0
  26. package/skills/temporal-architect-author-go/reference/options.md +138 -0
  27. package/skills/temporal-architect-author-go/reference/promise.md +73 -0
  28. package/skills/temporal-architect-author-go/reference/proto-driven.md +197 -0
  29. package/skills/temporal-architect-author-go/reference/query-handler.md +34 -0
  30. package/skills/temporal-architect-author-go/reference/signal-handler.md +73 -0
  31. package/skills/temporal-architect-author-go/reference/three-layer-testing.md +173 -0
  32. package/skills/temporal-architect-author-go/reference/types.md +72 -0
  33. package/skills/temporal-architect-author-go/reference/update-handler.md +64 -0
  34. package/skills/temporal-architect-author-go/reference/worker.md +215 -0
  35. package/skills/temporal-architect-author-go/reference/workflow-call.md +37 -0
  36. package/skills/temporal-architect-author-go/reference/workflow-def.md +45 -0
  37. package/skills/temporal-architect-author-infra/README.md +16 -0
  38. package/skills/temporal-architect-author-infra/SKILL.md +132 -0
  39. package/skills/temporal-architect-author-infra/reference/tcld.md +112 -0
  40. package/skills/temporal-architect-author-infra/reference/terraform.md +125 -0
  41. package/skills/temporal-architect-design/README.md +16 -0
  42. package/skills/temporal-architect-design/SKILL.md +224 -0
  43. package/skills/temporal-architect-design/reference/LANGUAGE.md +5 -0
  44. package/skills/temporal-architect-design/reference/anti-patterns.md +332 -0
  45. package/skills/temporal-architect-design/reference/common-errors.md +88 -0
  46. package/skills/temporal-architect-design/reference/core-principles.md +52 -0
  47. package/skills/temporal-architect-design/reference/design-checklist.md +59 -0
  48. package/skills/temporal-architect-design/reference/namespaces.md +84 -0
  49. package/skills/temporal-architect-design/reference/notation-examples.md +304 -0
  50. package/skills/temporal-architect-design/reference/notation-reference.md +70 -0
  51. package/skills/temporal-architect-design/reference/primitives-reference.md +65 -0
  52. package/skills/temporal-architect-design/reference/project-discovery-subagent.md +80 -0
  53. package/skills/temporal-architect-design/reference/reverse-engineering.md +53 -0
  54. package/skills/temporal-architect-design/reference/twf-conventions.md +43 -0
  55. package/skills/temporal-architect-design/reference/workflow-boundaries.md +43 -0
  56. package/skills/temporal-architect-design/topics/activities-advanced.md +358 -0
  57. package/skills/temporal-architect-design/topics/activities-advanced.twf +107 -0
  58. package/skills/temporal-architect-design/topics/child-workflows.md +347 -0
  59. package/skills/temporal-architect-design/topics/child-workflows.twf +171 -0
  60. package/skills/temporal-architect-design/topics/long-running.md +230 -0
  61. package/skills/temporal-architect-design/topics/long-running.twf +100 -0
  62. package/skills/temporal-architect-design/topics/nexus.md +248 -0
  63. package/skills/temporal-architect-design/topics/nexus.twf +148 -0
  64. package/skills/temporal-architect-design/topics/patterns.md +469 -0
  65. package/skills/temporal-architect-design/topics/patterns.twf +346 -0
  66. package/skills/temporal-architect-design/topics/promises-conditions.md +179 -0
  67. package/skills/temporal-architect-design/topics/promises-conditions.twf +213 -0
  68. package/skills/temporal-architect-design/topics/signals-queries-updates.md +319 -0
  69. package/skills/temporal-architect-design/topics/signals-queries-updates.twf +234 -0
  70. package/skills/temporal-architect-design/topics/task-queues.md +205 -0
  71. package/skills/temporal-architect-design/topics/task-queues.twf +184 -0
  72. package/skills/temporal-architect-design/topics/testing.md +437 -0
  73. package/skills/temporal-architect-design/topics/testing.twf +177 -0
  74. package/skills/temporal-architect-design/topics/timers-scheduling.md +131 -0
  75. package/skills/temporal-architect-design/topics/timers-scheduling.twf +129 -0
  76. package/skills/temporal-architect-design/topics/versioning.md +434 -0
  77. package/skills/temporal-architect-design/topics/versioning.twf +174 -0
@@ -0,0 +1,131 @@
1
+ # Timers and Scheduling
2
+
3
+ > **Example:** [`timers-scheduling.twf`](./timers-scheduling.twf)
4
+
5
+ Durable timing primitives for delays, deadlines, and recurring execution.
6
+
7
+ ## Timers
8
+
9
+ Durable sleep that survives worker restarts, deployments, and failures.
10
+
11
+ ### Basic Timer
12
+
13
+ ```twf
14
+ workflow DelayedNotification(userId: string, delay: duration):
15
+ # Durable sleep - workflow pauses but state is preserved
16
+ await timer(delay)
17
+
18
+ activity SendNotification(userId)
19
+ ```
20
+
21
+ ### Timer Considerations
22
+
23
+ | Aspect | Guidance |
24
+ |--------|----------|
25
+ | **Durability** | Timer survives worker restarts; workflow resumes when timer fires |
26
+ | **Precision** | Not precise to the millisecond; expect seconds of variance |
27
+ | **History** | Each timer adds to workflow history; avoid very frequent short timers |
28
+ | **Cancellation** | Timers can be cancelled if workflow is cancelled |
29
+
30
+ ---
31
+
32
+ ## Deadlines and Timeouts
33
+
34
+ ### Workflow-Level Deadline
35
+
36
+ ```twf
37
+ workflow OrderFulfillment(order: Order) -> (OrderResult):
38
+ # Entire workflow must complete within deadline (SDK-level config)
39
+ # workflow_timeout: 7d
40
+
41
+ activity ValidateRetailOrder(order)
42
+ await signal PaymentReceived
43
+ activity ShipRetailOrder(order)
44
+ close complete(OrderResult{status: "completed"})
45
+ ```
46
+
47
+ ### Operation Deadline Pattern
48
+
49
+ ```twf
50
+ workflow ProcessWithDeadline(data: Data) -> (Result):
51
+ # Race between operation and deadline
52
+ await one:
53
+ activity LongOperation(data) -> result:
54
+ close complete(Result{success: true, data: result})
55
+ timer(1h):
56
+ activity Cleanup(data)
57
+ close fail(Result{success: false, error: "deadline exceeded"})
58
+ ```
59
+
60
+ > **`await one` does not cancel the loser.** If the timer wins, `LongOperation` is **not** cancelled — it keeps running in the background until the workflow run ends. `await one` is "first to complete wins," not "winner cancels the rest." If the losing operation must actually stop (release a lock, stop billing), you need an explicit cancellation/cleanup activity — the race alone won't do it.
61
+
62
+ ### Timeout on Signal Wait
63
+
64
+ ```twf
65
+ workflow ApprovalWorkflow(request: Request) -> (Decision):
66
+ activity NotifyApprovers(request)
67
+
68
+ await one:
69
+ signal Approved:
70
+ close complete(Decision{status: "approved"})
71
+ signal Rejected:
72
+ close complete(Decision{status: "rejected"})
73
+ timer(7d):
74
+ activity NotifyExpired(request)
75
+ close complete(Decision{status: "expired"})
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Scheduling Patterns
81
+
82
+ ### Periodic Execution Within Workflow
83
+
84
+ ```twf
85
+ workflow Heartbeat(resourceId: string):
86
+ for:
87
+ activity CheckHealth(resourceId)
88
+ await timer(5m)
89
+ ```
90
+
91
+ ### Polling with Backoff
92
+
93
+ ```twf
94
+ workflow WaitForResource(resourceId: string) -> (Resource):
95
+ backoff = 1s
96
+ max_backoff = 5m
97
+
98
+ for:
99
+ activity CheckResource(resourceId) -> resource
100
+ if resource.ready:
101
+ close complete(resource)
102
+
103
+ await timer(backoff)
104
+ backoff = min(backoff * 2, max_backoff)
105
+ ```
106
+
107
+ ### Deadline with Periodic Check
108
+
109
+ ```twf
110
+ workflow WaitForCompletion(jobId: string) -> (JobResult):
111
+ for:
112
+ activity GetJobStatus(jobId) -> status
113
+ if status.complete:
114
+ close complete(JobResult{status: "complete", data: status.data})
115
+
116
+ await one:
117
+ timer(30s):
118
+ # Continue polling
119
+ timer(2h):
120
+ close fail(JobResult{status: "timeout"})
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Schedules (Cron Workflows)
126
+
127
+ Temporal Schedules execute workflows on a recurring basis (cron expressions, intervals, calendars). Schedules are **platform configuration**, not workflow design — they define *when* to start a workflow, not *how* it runs.
128
+
129
+ Schedule configuration (specs, overlap policies, catchup windows, timezones) is managed through the Temporal CLI or SDK, not TWF notation. See [Temporal Schedules documentation](https://docs.temporal.io/workflows#schedule) for details.
130
+
131
+ **Design implication:** A scheduled workflow should be designed like any other workflow — idempotent, with continue-as-new if long-running. The schedule itself is an external trigger, not part of the workflow's logic.
@@ -0,0 +1,129 @@
1
+ # Source: timers-scheduling.md
2
+ # Patterns: timer delay, deadline, polling with backoff, periodic
3
+
4
+ # --- Basic timer: delayed notification ---
5
+
6
+ workflow DelayedNotification(userId: string, delay: duration):
7
+ # Durable sleep - workflow pauses but state is preserved
8
+ await timer(delay)
9
+ activity SendNotification(userId)
10
+
11
+ # --- Deadline pattern: race between operation and timer ---
12
+
13
+ workflow ProcessWithDeadline(data: Data) -> (Result):
14
+ await one:
15
+ activity LongOperation(data) -> result:
16
+ close complete(Result{success: true, data: result})
17
+ timer(1h):
18
+ activity Cleanup(data)
19
+ close fail(Result{success: false, error: "deadline exceeded"})
20
+
21
+ # --- Periodic execution within workflow ---
22
+
23
+ workflow HealthMonitor(resourceId: string):
24
+ count = 0
25
+
26
+ for:
27
+ activity CheckHealth(resourceId)
28
+ await timer(5m)
29
+ count = count + 1
30
+ if (count > 1000):
31
+ close continue_as_new(resourceId)
32
+
33
+ # --- Polling with backoff ---
34
+
35
+ workflow WaitForResource(resourceId: string) -> (Resource):
36
+ backoff = 1s
37
+ maxBackoff = 60s
38
+
39
+ for:
40
+ activity CheckResource(resourceId) -> resource
41
+ if (resource.ready):
42
+ close complete(resource)
43
+
44
+ await one:
45
+ timer(backoff):
46
+ backoff = min(backoff * 2, maxBackoff)
47
+ timer(30m):
48
+ close fail(Resource{error: "timeout"})
49
+
50
+ # --- Deadline with periodic check ---
51
+
52
+ workflow WaitForCompletion(jobId: string) -> (JobResult):
53
+ checks = 0
54
+
55
+ for:
56
+ activity GetJobStatus(jobId) -> status
57
+ if (status.complete):
58
+ close complete(JobResult{status: "complete", data: status.data})
59
+
60
+ checks = checks + 1
61
+ if (checks > 100):
62
+ close complete(JobResult{status: "timeout"})
63
+
64
+ await timer(30s)
65
+
66
+ # --- Polling with continue-as-new for history management ---
67
+
68
+ workflow LongPoller(resourceId: string, iteration: int) -> (Resource):
69
+ count = 0
70
+
71
+ for:
72
+ activity PollResource(resourceId) -> status
73
+ if (status.ready):
74
+ activity FetchResource(resourceId) -> resource
75
+ close complete(resource)
76
+
77
+ await timer(5s)
78
+ count = count + 1
79
+ if (count >= 500):
80
+ close continue_as_new(resourceId, iteration + 1)
81
+
82
+ # --- Supporting activities ---
83
+
84
+ activity SendNotification(userId: string):
85
+ send(userId)
86
+
87
+ activity LongOperation(data: Data) -> (OperationResult):
88
+ return process(data)
89
+
90
+ activity Cleanup(data: Data):
91
+ cleanup(data)
92
+
93
+ activity CheckHealth(resourceId: string) -> (HealthStatus):
94
+ return check(resourceId)
95
+
96
+ activity CheckResource(resourceId: string) -> (Resource):
97
+ return check(resourceId)
98
+
99
+ activity GetJobStatus(jobId: string) -> (JobStatus):
100
+ return get_status(jobId)
101
+
102
+ activity PollResource(resourceId: string) -> (ResourceStatus):
103
+ return poll(resourceId)
104
+
105
+ activity FetchResource(resourceId: string) -> (Resource):
106
+ return fetch(resourceId)
107
+
108
+ # --- Worker and namespace ---
109
+
110
+ worker schedulingWorker:
111
+ workflow DelayedNotification
112
+ workflow ProcessWithDeadline
113
+ workflow HealthMonitor
114
+ workflow WaitForResource
115
+ workflow WaitForCompletion
116
+ workflow LongPoller
117
+ activity SendNotification
118
+ activity LongOperation
119
+ activity Cleanup
120
+ activity CheckHealth
121
+ activity CheckResource
122
+ activity GetJobStatus
123
+ activity PollResource
124
+ activity FetchResource
125
+
126
+ namespace scheduling:
127
+ worker schedulingWorker
128
+ options:
129
+ task_queue: "scheduling"
@@ -0,0 +1,434 @@
1
+ # Workflow Versioning and Evolution
2
+
3
+ > **Example:** [`versioning.twf`](./versioning.twf)
4
+
5
+ Safe strategies for evolving workflows without breaking running executions.
6
+
7
+ ## The Versioning Challenge
8
+
9
+ Running workflows may execute for hours, days, or months. When you deploy new code:
10
+
11
+ ```text
12
+ Problem:
13
+ 1. Workflow V1 starts, runs step A, B
14
+ 2. You deploy V2 (changes step B to B')
15
+ 3. Worker restarts, replays V1 workflow
16
+ 4. Replay expects B but code has B'
17
+ 5. Non-determinism error!
18
+ ```
19
+
20
+ **Solution:** Version-aware code that handles both old and new execution paths.
21
+
22
+ ---
23
+
24
+ ## Temporal's Versioning Approaches
25
+
26
+ | Approach | Use Case | Complexity |
27
+ |----------|----------|------------|
28
+ | **Patching API** | Incremental changes to existing workflows | Low |
29
+ | **Worker Versioning** | Major workflow changes, complete rewrites | Medium |
30
+ | **Workflow Type Versioning** | Breaking changes, parallel versions | Higher |
31
+
32
+ ---
33
+
34
+ ## Patching API
35
+
36
+ Add conditional logic to handle old vs new code paths during replay.
37
+
38
+ > **TWF vs SDK:** The `.twf` file ([`versioning.twf`](./versioning.twf)) uses boolean flag parameters for version gating — this is the DSL-level representation. The examples below use `patched("...")` which is the SDK-level API (Go: `workflow.GetVersion()`, Python: `patched()`). Both represent the same concept: branching on whether a workflow execution predates a code change.
39
+
40
+ ### Basic Pattern
41
+
42
+ ```pseudo
43
+ workflow UnderwritingAddFraudCheck(policy: Policy) -> (PolicyResult):
44
+ activity ValidatePolicy(policy)
45
+
46
+ # Version gate: new code only runs for new executions
47
+ if patched("add-fraud-check"):
48
+ activity FraudCheck(policy) # New step, only for new workflows
49
+
50
+ activity BindPolicy(policy)
51
+ close complete(PolicyResult{status: "complete"})
52
+ ```
53
+
54
+ ### How Patching Works
55
+
56
+ ```text
57
+ New Execution:
58
+ 1. patched("add-fraud-check") → true (marks in history)
59
+ 2. FraudCheck runs
60
+ 3. History: [Validate, Patch:add-fraud-check, FraudCheck, Payment]
61
+
62
+ Replay of Old Execution (started before patch):
63
+ 1. History has no patch marker
64
+ 2. patched("add-fraud-check") → false
65
+ 3. FraudCheck skipped
66
+ 4. Replay matches original history
67
+
68
+ Replay of New Execution (started after patch):
69
+ 1. History has patch marker
70
+ 2. patched("add-fraud-check") → true
71
+ 3. FraudCheck runs
72
+ 4. Replay matches history
73
+ ```
74
+
75
+ ### Patching Examples
76
+
77
+ **Adding a Step:**
78
+ ```pseudo
79
+ workflow Process(data: Data) -> (Result):
80
+ activity Step1(data)
81
+
82
+ if patched("v2-add-validation"):
83
+ activity NewValidation(data) # Added in V2
84
+
85
+ activity Step2(data)
86
+ close complete(Result{})
87
+ ```
88
+
89
+ **Removing a Step:**
90
+ ```pseudo
91
+ workflow Process(data: Data) -> (Result):
92
+ activity Step1(data)
93
+
94
+ if not patched("v3-remove-legacy"):
95
+ activity LegacyStep(data) # Removed in V3, but runs for old workflows
96
+
97
+ activity Step2(data)
98
+ close complete(Result{})
99
+ ```
100
+
101
+ **Changing a Step:**
102
+ ```pseudo
103
+ workflow Process(data: Data) -> (Result):
104
+ activity Step1(data)
105
+
106
+ if patched("v4-improved-processing"):
107
+ activity ImprovedProcessing(data)
108
+ else:
109
+ activity OldProcessing(data)
110
+
111
+ activity Step3(data)
112
+ close complete(Result{})
113
+ ```
114
+
115
+ ### Deprecating Patches
116
+
117
+ After all old workflows complete, remove patch:
118
+
119
+ > Note: Patch lifecycle management uses SDK-specific APIs. The concept is shown as pseudo-code.
120
+
121
+ ```pseudo
122
+ # Phase 1: Add patch (both paths exist)
123
+ if patched("add-feature"):
124
+ activity NewFeature()
125
+
126
+ # Phase 2: After all old workflows done, simplify
127
+ # (Run deprecate_patch to verify no old workflows)
128
+ if deprecated_patch("add-feature"):
129
+ pass # Old path, will error if any old workflows still running
130
+ activity NewFeature()
131
+
132
+ # Phase 3: Remove patch code entirely
133
+ activity NewFeature()
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Worker Versioning (Build IDs)
139
+
140
+ Route workflows to workers running compatible code versions.
141
+
142
+ ### Declaring the strategy in `.twf`
143
+
144
+ > **TWF vs SDK:** A worker instantiation declares *which* versioning strategy a worker pool uses via the `versioning` option — the design-altitude decision. The build-id registration, ramping, and routing mechanics below stay SDK/CLI-level (code-scale).
145
+
146
+ ```twf
147
+ namespace orders:
148
+ worker orderTypes
149
+ options:
150
+ task_queue: "orderProcessing"
151
+ versioning: build_id # none | build_id | deployment
152
+ ```
153
+
154
+ `versioning` expresses *intent* — the strategy a worker pool follows — not concrete Build IDs or deployment names (those are deploy-time inputs, never `.twf` content):
155
+
156
+ | Value | Meaning |
157
+ |-------|---------|
158
+ | `none` | Unversioned workers (default) |
159
+ | `build_id` | Build ID–based worker versioning |
160
+ | `deployment` | Worker Deployment–based versioning |
161
+
162
+ Enum values are bare idents — `build_id`, not `build-id` or `"build_id"`.
163
+
164
+ ### Concept
165
+
166
+ ```text
167
+ ┌─────────────────────────────────────────────────────┐
168
+ │ Task Queue │
169
+ ├─────────────────────────────────────────────────────┤
170
+ │ Build ID: 1.0 │ Build ID: 2.0 │ Build ID: 3.0 │
171
+ │ (default) │ (compatible) │ (latest) │
172
+ └────────┬────────┴────────┬────────┴────────┬───────┘
173
+ │ │ │
174
+ ┌───▼───┐ ┌────▼────┐ ┌────▼────┐
175
+ │Worker │ │ Worker │ │ Worker │
176
+ │ 1.0 │ │ 2.0 │ │ 3.0 │
177
+ └───────┘ └─────────┘ └─────────┘
178
+ ```
179
+
180
+ ### Configuration
181
+
182
+ ```bash
183
+ # Register build ID with task queue
184
+ temporal task-queue update-build-ids add-new-default \
185
+ --task-queue main-queue \
186
+ --build-id "v2.0"
187
+ ```
188
+
189
+ > Note: Worker configuration is SDK-level code.
190
+
191
+ ```pseudo
192
+ # Worker identifies its build ID
193
+ worker = Worker(
194
+ task_queue: "main-queue",
195
+ build_id: "v2.0",
196
+ workflows: [UnderwritingAddFraudCheck],
197
+ activities: [ValidatePolicy, FraudCheck, BindPolicy]
198
+ )
199
+ ```
200
+
201
+ ### Version Sets
202
+
203
+ ```bash
204
+ # Create version set: v1.0 and v1.1 are compatible
205
+ temporal task-queue update-build-ids add-new-compatible \
206
+ --task-queue main-queue \
207
+ --build-id "v1.1" \
208
+ --existing-compatible-build-id "v1.0"
209
+
210
+ # New version set: v2.0 is NOT compatible with v1.x
211
+ temporal task-queue update-build-ids add-new-default \
212
+ --task-queue main-queue \
213
+ --build-id "v2.0"
214
+ ```
215
+
216
+ ### Routing Behavior
217
+
218
+ | Workflow State | Routed To |
219
+ |----------------|-----------|
220
+ | New workflow | Latest default build ID |
221
+ | Running workflow | Same build ID (or compatible) |
222
+ | Workflow started on v1.0 | v1.0 or v1.1 worker |
223
+
224
+ ---
225
+
226
+ ## Workflow Type Versioning
227
+
228
+ Create a new workflow type for breaking changes.
229
+
230
+ ### Pattern
231
+
232
+ ```twf
233
+ # Version 1
234
+ workflow PolicyV1(policy: PolicyV1Input) -> (PolicyV1Result):
235
+ # Original implementation
236
+ ...
237
+
238
+ # Version 2 (breaking changes)
239
+ workflow PolicyV2(policy: PolicyV2Input) -> (PolicyV2Result):
240
+ # New implementation with different structure
241
+ ...
242
+ ```
243
+
244
+ ### Migration Strategy
245
+
246
+ > Note: API routing logic is application-level code, not TWF notation.
247
+
248
+ ```pseudo
249
+ # API layer routes to appropriate version
250
+ function startPolicyWorkflow(policy):
251
+ if policy.version == 1:
252
+ return client.start(PolicyV1, convertToV1(policy))
253
+ else:
254
+ return client.start(PolicyV2, convertToV2(policy))
255
+ ```
256
+
257
+ ### When to Use Workflow Type Versioning
258
+
259
+ | Scenario | Approach |
260
+ |----------|----------|
261
+ | Adding optional step | Patching |
262
+ | Changing activity order | Patching |
263
+ | Complete workflow rewrite | New workflow type |
264
+ | Input/output schema breaking change | New workflow type |
265
+ | Different business logic | New workflow type |
266
+
267
+ ---
268
+
269
+ ## Versioning Best Practices
270
+
271
+ ### 1. Plan for Evolution
272
+
273
+ ```pseudo
274
+ # Good: Named constants for versions (SDK-level code)
275
+ PATCH_ADD_FRAUD_CHECK = "2024-01-add-fraud-check"
276
+ PATCH_IMPROVE_VALIDATION = "2024-02-improve-validation"
277
+
278
+ workflow Process(data: Data):
279
+ if patched(PATCH_ADD_FRAUD_CHECK):
280
+ ...
281
+ ```
282
+
283
+ ### 2. Test Both Paths
284
+
285
+ ```pseudo
286
+ test "workflow handles both old and new path":
287
+ # Test new execution path
288
+ env = TestEnvironment()
289
+ result = env.execute(Workflow, input)
290
+ assert result.includesFraudCheck
291
+
292
+ # Test replay of old execution
293
+ old_history = load("workflow_v1.history")
294
+ replay_result = env.replay(Workflow, old_history)
295
+ assert replay_result.success # No non-determinism
296
+ ```
297
+
298
+ ### 3. Document Versions
299
+
300
+ ```text
301
+ # Workflow: UnderwritingAddFraudCheck
302
+ #
303
+ # Version History:
304
+ # - 2024-01: Added fraud check (patch: add-fraud-check)
305
+ # - 2024-02: Improved validation (patch: improve-validation)
306
+ # - 2024-03: Deprecated old validation (patch: remove-legacy-validation)
307
+ #
308
+ # Active patches: add-fraud-check, improve-validation
309
+ # Deprecated patches: remove-legacy-validation (safe to remove after 2024-04)
310
+ ```
311
+
312
+ ### 4. Monitor Old Workflows
313
+
314
+ ```bash
315
+ # Query for workflows started before patch
316
+ temporal workflow list \
317
+ --query "StartTime < '2024-01-15' AND ExecutionStatus = 'Running'"
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Common Versioning Scenarios
323
+
324
+ ### Adding Activity
325
+
326
+ ```pseudo
327
+ workflow Process(data: Data):
328
+ activity Existing1(data)
329
+
330
+ if patched("add-new-activity"):
331
+ activity NewActivity(data) # Safe to add
332
+
333
+ activity Existing2(data)
334
+ ```
335
+
336
+ ### Removing Activity
337
+
338
+ ```pseudo
339
+ workflow Process(data: Data):
340
+ activity Existing1(data)
341
+
342
+ if not patched("remove-deprecated"):
343
+ activity DeprecatedActivity(data) # Removed for new, kept for old
344
+
345
+ activity Existing2(data)
346
+ ```
347
+
348
+ ### Reordering Activities
349
+
350
+ ```pseudo
351
+ # Original order: A, B, C
352
+ # New order: A, C, B
353
+
354
+ workflow Process(data: Data):
355
+ activity A(data)
356
+
357
+ if patched("reorder-bc"):
358
+ activity C(data)
359
+ activity B(data)
360
+ else:
361
+ activity B(data)
362
+ activity C(data)
363
+ ```
364
+
365
+ ### Changing Activity Parameters
366
+
367
+ ```pseudo
368
+ workflow Process(data: Data):
369
+ if patched("new-activity-params"):
370
+ activity Enhanced(data, extraParam: true)
371
+ else:
372
+ activity Enhanced(data) # Old signature
373
+ ```
374
+
375
+ ---
376
+
377
+ ## Anti-Patterns
378
+
379
+ ### Unguarded Changes
380
+
381
+ ```pseudo
382
+ # BAD: Breaking change without version guard
383
+ workflow Process(data: Data):
384
+ activity Step1(data)
385
+ # Removed Step2 without patch - breaks replay!
386
+ activity Step3(data)
387
+
388
+ # GOOD: Version-guarded removal
389
+ workflow Process(data: Data):
390
+ activity Step1(data)
391
+ if not patched("remove-step2"):
392
+ activity Step2(data)
393
+ activity Step3(data)
394
+ ```
395
+
396
+ ### Too Many Active Patches
397
+
398
+ ```pseudo
399
+ # BAD: Accumulated complexity
400
+ workflow Process(data: Data):
401
+ if patched("v1"):
402
+ if patched("v2"):
403
+ if patched("v3"):
404
+ ...
405
+
406
+ # GOOD: Consolidate when safe, or use worker versioning
407
+ ```
408
+
409
+ ### Forgetting to Deprecate
410
+
411
+ ```pseudo
412
+ # BAD: Old patch code lives forever
413
+ if patched("feature-from-2020"): # All workflows with this are done!
414
+ ...
415
+
416
+ # GOOD: Clean up after old workflows complete
417
+ # 1. Verify no running workflows need old path
418
+ # 2. Replace with deprecated_patch
419
+ # 3. Remove patch code after verification
420
+ ```
421
+
422
+ ---
423
+
424
+ ## Version Migration Checklist
425
+
426
+ - [ ] Identify all changes from current version
427
+ - [ ] Classify each change (additive, removal, modification)
428
+ - [ ] Add appropriate patches for each change
429
+ - [ ] Write replay tests against old histories
430
+ - [ ] Deploy with both code paths active
431
+ - [ ] Monitor for non-determinism errors
432
+ - [ ] Wait for old workflows to complete
433
+ - [ ] Remove deprecated patch code
434
+ - [ ] Update documentation