Skip to content

Commit 81ee050

Browse files
committed
Restructure Instruqt assignments and add wrap-up resource chapter
This commit consolidates a top-level review pass over the eight chapter assignment files plus a new ninth chapter, syncs the assignment text with a TODO-numbering rework happening in `workshop-nexus-intro-code`, and fixes a Semgrep finding in the image build workflow. Assignment structure. Every chapter loses its `# Chapter N: ...` H1. Instruqt was rendering the YAML `title:` as the page header and the markdown H1 stacked underneath, producing the title twice on every page. The H1 is gone now; the YAML title is the single source. Section header rename. `## Why this chapter exists` (which read as weak in the lab UI) is now `## What You're Solving` across all eight chapters. Solution tab moves to the rightmost position. In chapters 2-7 the Solution tab was at index 1, immediately next to the Code Editor, and attendees were misclicking and editing the finished file. Solution now sits after every other tab (Worker terminals, Starter, Temporal UI). Every `(tab-N)` button reference in those chapters was renumbered to absorb the index shift. The "Stuck on a TODO" callouts gained a "(rightmost)" pointer and were converted from `[!TIP]` to `[!NOTE]` so Instruqt renders them as admonitions. Wrap-up rename and knowledge-check removal. `## Wrapping up` is now `## Key Takeaways` everywhere, and the trailing `> [!NOTE] Knowledge check:` blockquotes have been dropped from every chapter. The chapter-by-chapter quizzing role moves to the live AhaSlides deck; the in-lab text now ends on a forward-looking summary instead of unanswered questions. "Stop the Worker" steps removed. Each chapter's per-challenge `cleanup-workshop` already runs `pkill -f "payments.worker"` and `pkill -f "compliance.worker"` between challenges, so the trailing `## Step N: Stop the Worker(s)` step in chapters 1, 3, 4, 5, 6, 7, and 8 was redundant busywork. Those steps are gone; the surviving steps are still in correct numerical order. TODO sub-letter sync with the code repo. The companion change in `workshop-nexus-intro-code` rewrote exercise files to follow the "strip exactly what the user is asked to write; one TODO per insertion point; sub-letters when a logical step touches multiple locations" standard documented in `tmp/lessons-learned.md`. The assignment text mirrors that numbering: - Ch 2: Step 1 now walks TODOs 1a (decorator), 1b (`check_compliance` Operation), 1c (`submit_review` Operation). - Ch 3: Step 1 walks 2a (class decorator), 2b (`check_compliance` body), 2c (`submit_review` stub). - Ch 4: Step 1 walks 4a (remove unused import), 4b (replace activity call with Nexus call). Step 2 walks 5a (worker import), 5b (Activities list). - Ch 5: Step 2 walks 7a (convert handler) and 7b (delete dead import). - Ch 6: Step 1 walks 10a (init state), 10b (run-method branching), 10c (Update handler + validator). Step 2 walks 11a (`WorkflowHandle` import), 11b (`submit_review` body). Step 3 walks 12a/12b in `payments/workflows.py` and 12c/12d in `payments/worker.py` for the cross-file `ReviewCallerWorkflow` change. - Ch 7: Step 1 walks 13a (top-level `nexusrpc` import) and 13b (failure-injection branches). Code-Editor file path test. Chapter 2's Code Editor tab `path:` now points at `…/exercise/shared/service.py` directly instead of the chapter directory, to test whether Instruqt's `code` tab will open a specific file by default. The Instruqt docs only describe `path:` as a directory location, so this is a speculative experiment; if it works, the same change will roll out to the chapters that have a single primary edit target. New chapter 09-what-next. Added a Multiple Choice (`type: quiz`) challenge as the wrap-up after the polyglot demo. The body is a resource page with links to docs.temporal.io/nexus, learn.temporal.io, the per-language samples repos, the workshop's own code repo, follow-up patterns we did not have time to teach (in-workflow cancellation, `asyncio.shield`, Worker Versioning), and the community channels. The single answer is "Do you plan on using Nexus?" (Yes / No, both marked correct so the chapter passes either way and the response captures intent without gating progress). The old chapter-8 `> [!TIP] Where to go next` block was removed since those links now live in the wrap-up chapter. Loader-message tweak. `track.yml` line 33 dropped "the tardigrade" from the rehydrating Ziggy message, matching the wording on the other 30+ Ziggy lines. Build workflow Semgrep fix. `.github/workflows/build-image.yml` was flagged by Semgrep `yaml.github-actions.security.run-shell-injection` for interpolating `${{ github.ref_name }}` and `${{ env.IMAGE }}` directly into the `Compute image tags` shell script. The step now binds `REF_NAME` via a step-level `env:` block and reads `IMAGE` through its job-level env definition, so neither value is string-substituted into the shell. Semantics are unchanged. AhaSlides documentation tweak. `aha.md` updated to reflect that the Pattern Roulette spinner (slide 5) is now skipped during presentation. The slide remains in the deck (id 150153117) with `skip_when_presenting=True`; downstream slide numbering is unchanged. justfile. Added `slides-install`, `slides-dev`, and `slides-build` recipes for the Slidev deck. The `slides/` directory itself is not in this commit.
1 parent aacc34e commit 81ee050

13 files changed

Lines changed: 435 additions & 449 deletions

File tree

.github/workflows/build-image.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ jobs:
4141

4242
- name: Compute image tags
4343
id: tags
44+
env:
45+
REF_NAME: ${{ github.ref_name }}
4446
run: |
45-
if [ "${{ github.ref_name }}" = "main" ]; then
46-
echo "extra=${{ env.IMAGE }}:latest" >> "$GITHUB_OUTPUT"
47+
if [ "$REF_NAME" = "main" ]; then
48+
echo "extra=${IMAGE}:latest" >> "$GITHUB_OUTPUT"
4749
else
48-
echo "extra=${{ env.IMAGE }}:${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
50+
echo "extra=${IMAGE}:${REF_NAME}" >> "$GITHUB_OUTPUT"
4951
fi
5052
5153
- uses: docker/build-push-action@v6

aha.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ For each chapter, the presenter:
4444

4545
## Slide-by-slide integration guide
4646

47-
### Welcome block (Slides 1 to 5), maps to course-plan Welcome (9:00 to 9:05)
47+
### Welcome block (Slides 1 to 4), maps to course-plan Welcome (9:00 to 9:05)
4848

4949
| # | Type | Title / Prompt | When to trigger |
5050
| :- | :--- | :------------- | :-------------- |
5151
| 1 | Title | "Introduction to Temporal Nexus" | Open with this while attendees join. Show the QR code so people can scan to join. |
5252
| 2 | Word cloud | "One word for cross-team Temporal integration today." | First interactive moment. Sets the room. Read 3 to 5 responses out loud and riff. |
5353
| 3 | Scale (1 to 5) | "How comfortable are you with Temporal Workflows, Activities, and Updates?" | Lets the presenter calibrate pace. If average is below 3, slow down on the first chapter. |
5454
| 4 | Poll | "Have you ever wrapped a teammate's Workflow in an HTTP API?" | Run after the "why are we here" framing. The "yes, and it broke" responses are gold for the cross-team pain hook. |
55-
| 5 | Spinner wheel | "Pattern Roulette: 8 scenarios, defend your choice." | Optional crowd activity. Spin 2 or 3 times, ask volunteers to defend their pick. Pure energy moment, not graded. |
55+
| ~~5~~ | ~~Spinner wheel~~ | ~~"Pattern Roulette"~~ | **Skipped during presentation.** Slide remains in the editor (id 150153117) but `skip_when_presenting=True`. Slide numbering downstream is unchanged. |
5656

5757
### Chapter 1 graded checkpoint (Slides 6 to 12), maps to course-plan Activity 1.4 (Comp 1 Performance Assessment)
5858

instruqt/01-run-monolith/assignment.md

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ timelimit: 600
4848
enhanced_loading: false
4949
---
5050

51-
# Chapter 1: Run the Monolith
52-
5351
Before you decouple anything, run the application as it ships today and
5452
feel where the seams are. This chapter is observation only. There is no
5553
code to edit.
@@ -60,7 +58,7 @@ code to edit.
6058
> From Chapter 2 on, the **Code Editor** opens the exercise and a
6159
> separate **Solution** tab shows the finished file.
6260
63-
## Why this chapter exists
61+
## What You're Solving
6462

6563
Every distributed-systems story has a "before" picture, and this is ours.
6664

@@ -230,23 +228,7 @@ replace the Activity call with a **Nexus Operation** call: a typed
230228
remote-invocation primitive that runs in a different namespace, with a
231229
different worker, owned by a different team.
232230

233-
## Step 4: Stop the Worker
234-
235-
Back in the [button label="Worker" background="#444CE7"](tab-1)
236-
terminal, stop the Worker with `Ctrl+C` so it does not pollute the next
237-
chapter's task queue.
238-
239-
```bash,run
240-
# Press Ctrl+C in the Worker terminal.
241-
```
242-
243-
You can also stop it from the Starter terminal with:
244-
245-
```bash,run
246-
pkill -f "payments.worker" || true
247-
```
248-
249-
## Wrapping up
231+
## Key Takeaways
250232

251233
In this chapter you ran the application as it exists before any Nexus
252234
work. Three transactions executed end-to-end through a single Worker
@@ -259,18 +241,3 @@ Python interface that the Payments and Compliance teams will share, and
259241
the Nexus Endpoint that will route calls between them. The contract
260242
itself is small, and Chapter 2 is largely about what it means and where
261243
it lives. The actual decoupling happens across Chapters 3 and 4.
262-
263-
> [!NOTE]
264-
> Knowledge check (instructor-led in Live Event mode, self-check in
265-
> self-paced mode):
266-
>
267-
> - The four Nexus building blocks are **Service**, **Operation**,
268-
> **Endpoint**, and **Registry**. Try to predict which of those you
269-
> will define in code, which on the server, and which by importing
270-
> shared types.
271-
> - The synchronous Nexus handler deadline is **10 seconds**. Anything
272-
> that needs more time runs as an asynchronous, workflow-backed
273-
> operation (Chapter 5).
274-
> - The asynchronous Schedule-to-Close ceiling on Temporal Cloud is
275-
> **60 days**. Plenty of room for a human-in-the-loop review
276-
> (Chapter 6).

instruqt/02-service-contract/assignment.md

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,7 @@ tabs:
2828
title: Code Editor
2929
type: code
3030
hostname: workshop
31-
path: /root/workshop/exercises/02_service_contract/exercise
32-
- id: mkyu8fxrz4kn
33-
title: Solution
34-
type: code
35-
hostname: workshop
36-
path: /root/workshop/exercises/02_service_contract/solution
31+
path: /root/workshop/exercises/02_service_contract/exercise/shared/service.py
3732
- id: ystkhevci7d2
3833
title: Terminal
3934
type: terminal
@@ -44,19 +39,22 @@ tabs:
4439
type: service
4540
hostname: workshop
4641
port: 8233
42+
- id: mkyu8fxrz4kn
43+
title: Solution
44+
type: code
45+
hostname: workshop
46+
path: /root/workshop/exercises/02_service_contract/solution
4747
difficulty: basic
4848
timelimit: 1200
4949
enhanced_loading: false
5050
---
5151

52-
# Chapter 2: Define the Nexus Service Contract
53-
5452
In this chapter you define the shared Nexus Service contract between the
5553
Payments and Compliance teams, and stand up the routing infrastructure
5654
that will carry calls across the team boundary: a Nexus Endpoint that
5755
points callers at the Compliance team's task queue.
5856

59-
## Why this chapter exists
57+
## What You're Solving
6058

6159
Nexus exists so that two teams can call each other's Temporal code
6260
without sharing a codebase or a namespace. The mechanism that makes that
@@ -96,43 +94,52 @@ reads first when they want to call your Service.
9694
9795
## What you will do
9896

99-
- Apply **TODO 1** to add `@nexusrpc.service` and the typed Operation
100-
declarations to `shared/service.py`.
97+
- Apply **TODOs 1a–1c** to add `@nexusrpc.service` and the typed
98+
Operation declarations to `shared/service.py`.
10199
- Verify the two namespaces exist.
102100
- Create the `compliance-endpoint` Nexus Endpoint with the Temporal
103101
CLI, attaching a Markdown description from `compliance-endpoint.md`.
104102
- Find the Endpoint in the Web UI and read its Markdown description.
105103

106-
> [!TIP]
107-
> Stuck on a TODO? The **Solution** tab shows the finished file. Try
108-
> the exercise first, then peek if you need to.
104+
> [!NOTE]
105+
> Stuck on a TODO? The **Solution** tab (rightmost) shows the finished
106+
> file. Try the exercise first, then peek if you need to.
109107
110-
## Step 1: Apply TODO 1 in `shared/service.py`
108+
## Step 1: Apply TODOs 1a–1c in `shared/service.py`
111109

112110
Open `shared/service.py` in the
113111
[button label="Code Editor" background="#444CE7"](tab-0). The file
114-
contains a class `ComplianceNexusService` with a `pass` body and a
115-
TODO 1 comment.
112+
contains an empty `ComplianceNexusService` class with three TODO
113+
markers.
114+
115+
### TODO 1a: Decorate the class
116116

117-
Three changes:
117+
Add `@nexusrpc.service` directly above the `class ComplianceNexusService:`
118+
line:
118119

119-
1. Add `@nexusrpc.service` directly above the `class
120-
ComplianceNexusService:` line.
121-
2. Replace the TODO 1 comment with the typed `check_compliance`
122-
Operation:
120+
```python
121+
@nexusrpc.service
122+
class ComplianceNexusService:
123+
```
123124

124-
```python
125-
check_compliance: nexusrpc.Operation[ComplianceRequest, ComplianceResult]
126-
```
125+
### TODO 1b: Declare the `check_compliance` Operation
127126

128-
3. Add the typed `submit_review` Operation directly below it:
127+
Inside the class body, add the typed Operation:
128+
129+
```python
130+
check_compliance: nexusrpc.Operation[ComplianceRequest, ComplianceResult]
131+
```
129132

130-
```python
131-
submit_review: nexusrpc.Operation[ReviewRequest, ComplianceResult]
132-
```
133+
### TODO 1c: Declare the `submit_review` Operation
133134

134-
You can remove the `pass` line. The class no longer needs it once the
135-
operations are declared.
135+
Directly below it, add:
136+
137+
```python
138+
submit_review: nexusrpc.Operation[ReviewRequest, ComplianceResult]
139+
```
140+
141+
You can remove the `pass` line once both operations are declared. The
142+
class no longer needs it.
136143

137144
After your edits, the relevant block should look like:
138145

@@ -168,7 +175,7 @@ environment with separate workflows, separate task queues, and separate
168175
access control. **Nexus is the only thing that crosses the boundary.**
169176

170177
Both namespaces were created for you when the track started. Verify
171-
they exist. In the [button label="Terminal" background="#444CE7"](tab-2):
178+
they exist. In the [button label="Terminal" background="#444CE7"](tab-1):
172179

173180
```bash,run
174181
temporal operator namespace list
@@ -214,7 +221,7 @@ The `get` output should include the Markdown description from
214221

215222
## Step 4: Find the Endpoint in the Web UI
216223

217-
Click the [button label="Temporal UI" background="#444CE7"](tab-3)
224+
Click the [button label="Temporal UI" background="#444CE7"](tab-2)
218225
tab. In the left navigation, click **Nexus Endpoints** (or browse to
219226
`/nexus/endpoints` directly).
220227

@@ -227,7 +234,7 @@ exposes before writing a caller workflow against it.**
227234
The Endpoint exists at the cluster level. It is not scoped to any one
228235
namespace. That is what lets it bridge teams.
229236

230-
## Wrapping up
237+
## Key Takeaways
231238

232239
You wrote the contract that the Payments and Compliance teams will
233240
share, and you registered the routing rule that the dev server will use
@@ -246,13 +253,3 @@ Compliance Worker that polls the `compliance-risk` task queue.
246253
> take. The contract has no UI surface; it lives only in the Python
247254
> files both teams import. The Endpoint is the matching server-side
248255
> artifact, plus a description that documents what the contract does.
249-
250-
> [!NOTE]
251-
> Knowledge check (instructor-led in Live Event mode, self-check in
252-
> self-paced mode):
253-
>
254-
> - Where does the Service contract live, and which packages import it?
255-
> - Which artifact does the Web UI show: the Service class, the
256-
> Endpoint, or both?
257-
> - If you change the contract, do you need to restart the dev server
258-
> or just the Workers that import it?

0 commit comments

Comments
 (0)