@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,230 @@
1
+ # Long-Running Workflows
2
+
3
+ > **Example:** [`long-running.twf`](./long-running.twf)
4
+
5
+ Patterns for workflows that run for extended periods: continue-as-new, history management, and entity workflows.
6
+
7
+ ## The History Problem
8
+
9
+ Temporal replays the full event history to reconstruct workflow state after any restart. This is the **primary constraint** on long-running workflows — history size directly determines replay cost, and Temporal enforces a hard limit (~50MB / ~50K events).
10
+
11
+ | Issue | Impact |
12
+ |-------|--------|
13
+ | Replay cost | **Entire history replayed on every recovery** — this is the main bottleneck |
14
+ | Hard limit | ~50MB event history / ~50K events — workflow terminates if exceeded |
15
+ | Memory | Full history loaded into worker memory during replay |
16
+ | Latency | Longer history = slower recovery after worker restart |
17
+
18
+ **Solution:** Reset history periodically with `continue_as_new`.
19
+
20
+ > **A bound is not a free pass.** "Only infinite loops need `continue_as_new`" is wrong. A *bounded* loop still grows history linearly with its bound, and if per-iteration history is chunky (a large activity result plus several tool calls each iteration) it can hit the limit well before the bound. The rule is: **loops whose accumulated history is large need `continue_as_new` — the bound alone is not sufficient.**
21
+ >
22
+ > **State the strategy explicitly.** Even though *where* to continue-as-new is partly an implementation concern, the design should **say** what it is — "bounded at N, per-iteration history small, no `continue_as_new`," "resets every K iterations," or "defer to author-go" — rather than leaving it silent. A silent design is one nobody decided.
23
+
24
+ ---
25
+
26
+ ## Continue-As-New
27
+
28
+ Atomically complete current workflow and start a new execution with fresh history, preserving logical continuity.
29
+
30
+ ### Basic Pattern
31
+
32
+ ```twf
33
+ workflow LongRunningProcessor(processor: Processor):
34
+ eventCount = 0
35
+
36
+ for:
37
+ await signal NewEvent -> (event)
38
+ activity ProcessEvent(event)
39
+ processor.processed += 1
40
+ eventCount += 1
41
+
42
+ # Reset history before it gets too large
43
+ if eventCount >= 1000:
44
+ close continue_as_new(processor) # Fresh history, same logical workflow
45
+ ```
46
+
47
+ ### Continue-As-New Semantics
48
+
49
+ | Aspect | Behavior |
50
+ |--------|----------|
51
+ | Workflow ID | Same (logical continuity) |
52
+ | Run ID | New (fresh execution) |
53
+ | History | Reset to zero |
54
+ | Pending signals | Carried over (configurable) |
55
+ | State | Passed as input to new execution |
56
+
57
+ ### When to Continue-As-New
58
+
59
+ | Trigger | Example |
60
+ |---------|---------|
61
+ | Event count | After processing N events |
62
+ | Time-based | Every 24 hours |
63
+ | History size | Approaching limit |
64
+ | Periodic reset | End of billing cycle |
65
+
66
+ ### SDK Intrinsics for History Tracking
67
+
68
+ These deterministic SDK functions are available in workflow code (not activities) for deciding when to continue-as-new:
69
+
70
+ | Function | Returns | Use |
71
+ |----------|---------|-----|
72
+ | `workflow.history_length()` | Event count | Compare against threshold (e.g., `>= 1000`) |
73
+ | `workflow.history_size()` | Bytes | Compare against limit (e.g., `> 40_000_000`) |
74
+
75
+ These appear in TWF as raw expressions since they're SDK-level calls, not TWF keywords.
76
+
77
+ ### Data Serialization
78
+
79
+ ```twf
80
+ workflow EntityWorkflow(entity: Entity, data: EntityData):
81
+ for:
82
+ await signal Command -> (command)
83
+ data = applyCommand(data, command)
84
+
85
+ # Periodic continuation with current data
86
+ if should_continue():
87
+ close continue_as_new(entity, data)
88
+ ```
89
+
90
+ > Note: Data structs are defined at the SDK level, not in TWF notation.
91
+
92
+ ```pseudo
93
+ # Data must be serializable!
94
+ struct EntityData:
95
+ balance: decimal
96
+ lastUpdated: timestamp
97
+ pendingOperations: []Operation
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Entity Workflow Pattern
103
+
104
+ Long-lived workflow representing a business entity (user, order, account, subscription).
105
+
106
+ ### Structure
107
+
108
+ ```twf
109
+ workflow UserEntity(userId: string, user: User):
110
+ # Initialize user if new
111
+ if user == null:
112
+ activity LoadUser(userId) -> (user)
113
+
114
+ query GetUser() -> (User):
115
+ return user
116
+
117
+ update UpdateSettings(settings: Settings) -> (Result):
118
+ user.settings = settings
119
+ return Result{success: true}
120
+
121
+ for:
122
+ # Wait for commands or periodic triggers
123
+ await one:
124
+ signal UpdateProfile:
125
+ user.profile = signal.data
126
+
127
+ signal AddCredits:
128
+ user.credits += signal.amount
129
+
130
+ signal Deactivate:
131
+ user.active = false
132
+ close complete # End entity lifecycle
133
+
134
+ timer(24h):
135
+ # Periodic maintenance
136
+
137
+ # Persist after any change
138
+ activity PersistUser(user)
139
+
140
+ # Continue-as-new periodically
141
+ if eventCount > 500:
142
+ close continue_as_new(userId, user)
143
+ ```
144
+
145
+ ### Entity Lifecycle
146
+
147
+ > Note: Entity lifecycle management uses SDK-level API calls, not TWF notation.
148
+
149
+ ```pseudo
150
+ # Create entity (start workflow)
151
+ temporal.start_workflow(
152
+ workflow: UserEntity,
153
+ id: "user-{userId}",
154
+ input: {userId: userId, user: null}
155
+ )
156
+
157
+ # Interact with entity (signals, queries, updates)
158
+ temporal.signal("user-{userId}", UpdateProfile, {name: "Alice"})
159
+ user = temporal.query("user-{userId}", GetUser)
160
+ result = temporal.update("user-{userId}", AddCredits, {amount: 100})
161
+
162
+ # Entity continues until explicit termination
163
+ temporal.signal("user-{userId}", Deactivate, {})
164
+ ```
165
+
166
+ ### Entity vs Process Workflows
167
+
168
+ | Entity Workflow | Process Workflow |
169
+ |-----------------|------------------|
170
+ | Long-lived (days, months, years) | Short-lived (minutes, hours) |
171
+ | Represents a thing | Represents a process |
172
+ | Reacts to external events | Drives toward completion |
173
+ | No natural end state | Has completion state |
174
+ | Examples: User, Account, Subscription | Examples: Order, Deployment, Migration |
175
+
176
+ ---
177
+
178
+ ## Continue-As-New Anti-Patterns
179
+
180
+ ### Losing Data on Continue
181
+
182
+ ```twf
183
+ # BAD: Data not passed to continuation
184
+ workflow Processor(data: ProcessorData):
185
+ modifiedData = transform(data)
186
+ close continue_as_new() # Lost modifiedData!
187
+
188
+ # GOOD: Pass current data
189
+ workflow Processor(data: ProcessorData):
190
+ modifiedData = transform(data)
191
+ close continue_as_new(modifiedData)
192
+ ```
193
+
194
+ ### Continue-As-New in Wrong Place
195
+
196
+ ```twf
197
+ # BAD: Continue in middle of operation
198
+ workflow Processor(data: ProcessorData):
199
+ activity Step1()
200
+ if shouldContinue:
201
+ close continue_as_new(data) # Step2 never runs!
202
+ activity Step2()
203
+
204
+ # GOOD: Continue at natural boundary
205
+ workflow Processor(data: ProcessorData):
206
+ activity Step1()
207
+ activity Step2()
208
+ if shouldContinue:
209
+ close continue_as_new(data)
210
+ ```
211
+
212
+ ### Too Frequent Continuation
213
+
214
+ ```twf
215
+ # BAD: Continue every event
216
+ workflow Processor(data: ProcessorData):
217
+ event = await signal Event
218
+ process(event)
219
+ close continue_as_new(data) # Unnecessary overhead!
220
+
221
+ # GOOD: Batch before continuing
222
+ workflow Processor(data: ProcessorData):
223
+ count = 0
224
+ for:
225
+ event = await signal Event
226
+ process(event)
227
+ count += 1
228
+ if count >= 1000:
229
+ close continue_as_new(data)
230
+ ```
@@ -0,0 +1,100 @@
1
+ # Source: long-running.md
2
+ # Patterns: continue_as_new, entity workflow, signal/query/update
3
+
4
+ # --- Basic continue-as-new pattern ---
5
+
6
+ workflow LongRunningProcessor(processor: Processor):
7
+ signal NewEvent(data: EventData):
8
+ processor.lastEvent = data
9
+
10
+ eventCount = 0
11
+
12
+ for:
13
+ await one:
14
+ signal NewEvent:
15
+ activity ProcessEvent(processor) -> result
16
+ processor.processed = processor.processed + 1
17
+ eventCount = eventCount + 1
18
+ timer(24h):
19
+ activity PeriodicCheck(processor)
20
+
21
+ # Reset history before it gets too large
22
+ if (eventCount >= 1000):
23
+ close continue_as_new(processor)
24
+
25
+ # --- Entity workflow pattern ---
26
+
27
+ workflow UserEntity(userId: string, user: User):
28
+ signal UpdateProfile(data: ProfileData):
29
+ user.profile = data
30
+
31
+ signal AddCredits(amount: decimal):
32
+ user.credits = user.credits + amount
33
+
34
+ signal Deactivate():
35
+ user.active = false
36
+
37
+ query GetUser() -> (User):
38
+ return user
39
+
40
+ update UpdateSettings(settings: Settings) -> (Result):
41
+ user.settings = settings
42
+ activity PersistUser(user)
43
+ return Result{success: true}
44
+
45
+ # Initialize user if new
46
+ if (user == null):
47
+ activity LoadUser(userId) -> user
48
+
49
+ eventCount = 0
50
+
51
+ for:
52
+ await one:
53
+ signal UpdateProfile:
54
+ activity PersistUser(user)
55
+ signal AddCredits:
56
+ activity PersistUser(user)
57
+ signal Deactivate:
58
+ activity PersistUser(user)
59
+ close complete
60
+ timer(24h):
61
+ activity DailyMaintenance(user)
62
+
63
+ eventCount = eventCount + 1
64
+
65
+ # Continue-as-new periodically
66
+ if (eventCount > 500):
67
+ close continue_as_new(userId, user)
68
+
69
+ # --- Supporting activities ---
70
+
71
+ activity ProcessEvent(processor: Processor) -> (EventResult):
72
+ return process(processor)
73
+
74
+ activity LoadUser(userId: string) -> (User):
75
+ return db.load(userId)
76
+
77
+ activity PersistUser(user: User):
78
+ db.save(user.id, user)
79
+
80
+ activity DailyMaintenance(user: User):
81
+ run_maintenance(user.id, user)
82
+
83
+ activity PeriodicCheck(processor: Processor):
84
+ check(processor)
85
+
86
+ # --- Worker and namespace ---
87
+
88
+ worker longRunningWorker:
89
+ workflow LongRunningProcessor
90
+ workflow UserEntity
91
+ activity ProcessEvent
92
+ activity LoadUser
93
+ activity PersistUser
94
+ activity DailyMaintenance
95
+ activity PeriodicCheck
96
+
97
+ namespace longRunning:
98
+ worker longRunningWorker
99
+ options:
100
+ task_queue: "long-running"
@@ -0,0 +1,248 @@
1
+ # Nexus: Cross-Namespace Communication
2
+
3
+ > **Example:** [`nexus.twf`](./nexus.twf)
4
+
5
+ Nexus enables workflows in one Temporal namespace to call operations in another namespace, with proper authorization and abstraction.
6
+
7
+ ## When to Use Nexus
8
+
9
+ | Use Nexus | Use Child Workflow Instead |
10
+ |-----------|---------------------------|
11
+ | Cross-namespace calls | Same namespace |
12
+ | Cross-team boundaries | Same team |
13
+ | Different security contexts | Same security context |
14
+ | Service abstraction needed | Direct coupling acceptable |
15
+ | Multi-tenant architectures | Single-tenant |
16
+
17
+ > **Deciding how many namespaces?** See [namespaces.md](../reference/namespaces.md) — the default is **one**. Nexus is the mechanism for the *one* case that legitimately spans namespaces (a cross-team / different-security-context service contract); it is not a reason to multiply namespaces. Same-namespace calls should be child workflows, not Nexus.
18
+
19
+ ---
20
+
21
+ ## Nexus Concepts
22
+
23
+ ### Architecture
24
+
25
+ ```text
26
+ orders Namespace (Caller)
27
+ OrderCheckout Workflow
28
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(args) -> result
29
+ |
30
+ v (cross-namespace)
31
+ payments Namespace (Target)
32
+ PaymentsEndpoint (task_queue: "payments")
33
+ PaymentsService
34
+ async ProcessPayment -> starts ProcessPaymentWorkflow
35
+
36
+ orders Namespace (Caller)
37
+ OrderCheckout Workflow
38
+ detach nexus NotificationsEndpoint NotificationsService.SendConfirmation(args)
39
+ |
40
+ v (cross-namespace)
41
+ notifications Namespace (Target)
42
+ NotificationsEndpoint (task_queue: "notifications")
43
+ NotificationsService
44
+ async SendConfirmation -> starts SendConfirmationWorkflow
45
+ ```
46
+
47
+ ### Components
48
+
49
+ | Component | TWF Construct | Description |
50
+ |-----------|--------------|-------------|
51
+ | **Nexus Service** | `nexus service Name:` | Top-level definition with operations |
52
+ | **Async Operation** | `async OpName workflow WorkflowName` | Delegates to a named workflow |
53
+ | **Sync Operation** | `sync OpName(params) -> (Type):` | Runs inline with a body |
54
+ | **Nexus Endpoint** | `nexus endpoint Name` (in namespace) | Deployment routing with `task_queue` |
55
+ | **Service Reference** | `nexus service Name` (in worker) | Links service to worker |
56
+ | **Nexus Call** | `nexus Endpoint Service.Op(args)` | Invokes an operation |
57
+
58
+ ---
59
+
60
+ ## Nexus Service Definition
61
+
62
+ Define a nexus service with typed operations:
63
+
64
+ ```twf
65
+ nexus service PaymentsService:
66
+ async ProcessPayment workflow ProcessPaymentWorkflow
67
+ sync GetPaymentStatus(paymentId: string) -> (PaymentStatus):
68
+ activity LookupPayment(paymentId) -> status
69
+ close complete(status)
70
+ ```
71
+
72
+ - **Async operations** delegate to a named workflow (one-liner, no body)
73
+ - **Sync operations** have a body using the workflow statement set
74
+
75
+ ### Deployment
76
+
77
+ Each Nexus service lives in its own namespace. The endpoint is defined alongside the worker that serves it, in the target namespace. The caller namespace only hosts the workflows that invoke the endpoints.
78
+
79
+ ```twf
80
+ worker paymentProcessingWorker:
81
+ workflow ProcessPaymentWorkflow
82
+ activity LookupPayment
83
+ nexus service PaymentsService
84
+
85
+ # Target namespace: owns the service and exposes the endpoint
86
+ namespace payments:
87
+ worker paymentProcessingWorker
88
+ options:
89
+ task_queue: "payments"
90
+ nexus endpoint PaymentsEndpoint
91
+ options:
92
+ task_queue: "payments"
93
+
94
+ # Caller namespace: only has the workflows that call into payments
95
+ namespace orders:
96
+ worker checkoutWorker
97
+ options:
98
+ task_queue: "checkout"
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Nexus Call Syntax
104
+
105
+ ### Basic Call
106
+
107
+ ```twf
108
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(order.payment) -> result
109
+ ```
110
+
111
+ Three identifiers: `Endpoint Service.Operation(args)` — endpoint name, then service and operation separated by a dot.
112
+
113
+ ### With Options
114
+
115
+ ```twf
116
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(payment) -> result
117
+ options:
118
+ schedule_to_close_timeout: 5m
119
+ ```
120
+
121
+ Options: `schedule_to_close_timeout`, `retry_policy`, `priority`.
122
+
123
+ ---
124
+
125
+ ## Execution Modes
126
+
127
+ Nexus calls support the same three execution modes as child workflows:
128
+
129
+ | Mode | Syntax | Behavior |
130
+ |------|--------|----------|
131
+ | **Synchronous** | `nexus Ep Svc.Op(args) -> result` | Caller blocks until operation completes |
132
+ | **Async (promise)** | `promise p <- nexus Ep Svc.Op(args)` | Caller continues, awaits promise later |
133
+ | **Fire-and-forget** | `detach nexus Ep Svc.Op(args)` | Caller continues, never waits |
134
+
135
+ ### Synchronous (Default)
136
+
137
+ ```twf
138
+ workflow Caller(order: Order) -> (Result):
139
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(order.payment) -> result
140
+ close complete(Result{paymentId: result.id})
141
+ ```
142
+
143
+ ### Asynchronous (Promise)
144
+
145
+ ```twf
146
+ workflow Caller(data: Data) -> (Result):
147
+ promise handle <- nexus PaymentsEndpoint PaymentsService.ProcessPayment(data.payment)
148
+ activity DoOtherWork(data) -> localResult
149
+ await handle -> paymentResult
150
+ close complete(Result{localResult, paymentResult})
151
+ ```
152
+
153
+ ### Fire-and-Forget (Detach)
154
+
155
+ ```twf
156
+ workflow Caller(order: Order) -> (Result):
157
+ detach nexus NotificationsEndpoint NotificationsService.SendConfirmation(order.customer)
158
+ close complete(Result{status: "initiated"})
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Await Patterns
164
+
165
+ ### Await Nexus
166
+
167
+ ```twf
168
+ await nexus PaymentsEndpoint PaymentsService.GetStatus(id) -> status
169
+ ```
170
+
171
+ ### Await One with Nexus
172
+
173
+ Race a nexus call against a timeout:
174
+
175
+ ```twf
176
+ workflow Caller(data: Data) -> (Result):
177
+ await one:
178
+ nexus PaymentsEndpoint PaymentsService.ProcessPayment(data) -> result:
179
+ close complete(Result{success: true, data: result})
180
+ timer(5m):
181
+ activity AlertTimeout(data)
182
+ close fail(Result{success: false, error: "timeout"})
183
+ ```
184
+
185
+ > **The nexus operation continues if the timer wins.** Losing an `await one` race does **not** cancel the nexus call — the operation (and the workflow it runs in the *target* namespace) keeps running until this workflow run ends. Since the target is an independent service, you usually can't cancel it implicitly; if the payment must be voided on timeout, model that explicitly (a compensating nexus op or activity), not by relying on the race.
186
+
187
+ ---
188
+
189
+ ## Resolution
190
+
191
+ The resolver validates all nexus references:
192
+
193
+ ### Errors
194
+
195
+ | Condition | Error |
196
+ |-----------|-------|
197
+ | Duplicate `nexus service` name | `duplicate nexus service definition: X` |
198
+ | Duplicate endpoint name across namespaces | `duplicate nexus endpoint name "X"` |
199
+ | Endpoint not found (endpoints exist) | `undefined nexus endpoint: X` |
200
+ | Service not found (services exist) | `undefined nexus service: X` |
201
+ | Operation not found on service | `nexus service X has no operation Y` |
202
+ | `detach nexus ... -> result` | `detach nexus call cannot have a result` |
203
+ | Async op references missing workflow | `async operation Y references undefined workflow: Z` |
204
+ | Worker refs missing service | `worker W references undefined nexus service: X` |
205
+ | Endpoint missing `task_queue` | `nexus endpoint X missing required task_queue option` |
206
+ | Endpoint task queue has no worker with service | `no worker on that queue has service S` |
207
+
208
+ ### Warnings
209
+
210
+ | Condition | Warning |
211
+ |-----------|---------|
212
+ | Service not on any worker (namespaces exist) | `nexus service X is not referenced by any worker` |
213
+ | Endpoint not found (no endpoints defined) | `unresolved nexus endpoint: X (may be external)` |
214
+ | Service not found (no services defined) | `unresolved nexus service: X (may be external)` |
215
+
216
+ ---
217
+
218
+ ## Anti-Patterns
219
+
220
+ ### Nexus for Same-Namespace Calls
221
+
222
+ Nexus adds routing and authorization overhead that is only justified across namespace boundaries. Calling a service in the same namespace should use a child workflow instead.
223
+
224
+ ```twf
225
+ # BAD: Nexus overhead for a call that stays inside the orders namespace
226
+ workflow OrderCheckout(order: Order) -> (OrderResult):
227
+ nexus LocalEndpoint LocalService.Validate(order) -> result
228
+
229
+ # GOOD: Child workflow — same namespace, same team, no boundary to cross
230
+ workflow OrderCheckout(order: Order) -> (OrderResult):
231
+ workflow ValidateOrder(order) -> result
232
+ ```
233
+
234
+ ### Missing Timeout
235
+
236
+ ```twf
237
+ # BAD: No deadline
238
+ workflow A():
239
+ nexus Endpoint Svc.SlowOperation(data) -> result
240
+
241
+ # GOOD: Explicit deadline via await one
242
+ workflow A():
243
+ await one:
244
+ nexus Endpoint Svc.SlowOperation(data) -> result:
245
+ close complete(Result{result})
246
+ timer(5m):
247
+ close fail(Result{error: "timeout"})
248
+ ```