Init#1
Conversation
A sub-agent swarm audited each chapter's assignment.md against the workshop-nexus-intro-code exercise/solution sources, the samples-python and samples-java repos, and the Temporal docs MCP. The findings were synthesized into audit-report.md, then applied chapter by chapter. Critical fixes. Chapter 1's startup banner, transaction descriptions, result strings, and one-line output format were all fabrications that did not match what payments/worker.py and payments/starter.py actually print. Replaced the banner verbatim, rewrote the TXN-A/B/C descriptions to match the real $250/$12,000/$75,000 amounts and US-US/US-UK/US-US routes, and swapped the fake one-liner output for the real multi-line Result/Risk/Reason block. The TXN-C decline reason now correctly cites the over-$50,000 threshold rule rather than a fabricated sanctions hit, and the Result string is DECLINED_COMPLIANCE. The same fabricated output block was duplicated in Chapter 8 and got the same fix. Chapters 1 and 3 also referred to a non-existent payments-task-queue task queue; corrected to payments-processing in three places. Chapter 8 polyglot annotation contract. Added the failure-mode names the cross-language contract relies on: NOT_FOUND: Unrecognized operation if Java drops @operation(name = ...) and UnrecognizedPropertyException if it drops @JsonProperty. Listed the four Java source files with full paths so attendees can find the annotated data classes. Added a one-line Jackson-via-temporal-sdk transitive note. Named the three Nexus events (Scheduled, Started, Completed) explicitly in the inspection step so attendees see byte-for-byte equivalence with the pure-Python run. Bumped setup-workshop with a target/ rebuild guard so the demo survives a cache miss on the baked image. Per-chapter polish. Chapter 2 gained a one-liner explaining why the contract lives in shared/ (neither team owns it), and the description-file path in solve-workshop was aligned to absolute. Chapter 4 softened the "wired up the Nexus client" wording (Nexus clients are created in workflow code at runtime, not registered on the Worker) and added a forward reference explaining that TXN-B's MEDIUM auto-approval is a property of the rule-based sync handler we will replace in Chapter 6. Chapter 4's solve-workshop sleeps were bumped from 3s to 5s for cold-VM resilience. Chapter 5 instructs attendees to delete the now-dead _check_compliance import and uses the real multi-line worker banner in place of a one-line snippet. Chapter 6 added a namespace clarification for nexus.client() (it returns the handler-namespace-bound Client, which is the right one for the cross-namespace Update) and made the Step 8 namespace-selector instruction explicit. Chapter 7 added the rationale for terminate() vs cancel() in scenario B (a BackingOff Nexus operation would not surface a cancel until its next attempt), added the sync-operation-cannot-be-canceled caveat plus the WAIT_CANCELLATION_REQUESTED proto-name aside, and dropped the "~" from "60 seconds" since the docs are exact. Verification. All eight assignment.md files contain zero em-dashes, zero remaining payments-task-queue references, and zero references to the fabricated "sanctioned destination" decline reason. Every verbatim code snippet, banner, and event-name claim was checked against the corresponding source file or the Temporal docs MCP.
This commit captures the round-trip with Instruqt that turned the local track into a live one, plus the rendering fixes that fell out of seeing it in the sandbox. Track metadata. After the first push, Instruqt assigned ids to the track itself, every challenge, and every tab; those ids are now committed back into track.yml and each chapter's assignment.md so subsequent pushes update the same artifacts. The track was renamed to "Replay 2026 Nexus Workshop" with slug `replay26-nexus`. The loadingMessages field was promoted from the boolean default to a list of 35 Ziggy-and-tardigrade-themed messages. Other YAML reformatting in track.yml (folded scalars, list indentation, the assigned checksum, the enhanced_loading flag) is the CLI's canonical output and will reappear on every pull, so it is taken as-is rather than fought. Image tag. instruqt/config.yml is pinned to ghcr.io/temporalio/workshop-nexus-intro-sandbox:init while content stabilizes on the init branch. It will flip back to :latest when init merges to main. Rendering fixes. Instruqt's markdown renderer treated the `=========================================================` separator lines inside fenced output blocks as Setext H1 syntax, which exploded the layout and triggered the renderer to fold the broken block behind a chevron. The separator lines are dropped in every banner snippet across all chapters. Output fenced blocks are switched from ```output to ```bash,nocopy per the Instruqt markdown editor docs; attendees get monospace formatting and bash-flavored coloring without the misleading copy button on text that is not meant to be copied. Heading hierarchy. The body `# Chapter N: Title` line is dropped from every assignment, since Instruqt already renders the page title from the `title:` field in the frontmatter. All `## Step N:` and sibling section headings are promoted to `# `, and `### Subsection` headings (Ch 6 substeps, Ch 7 scenario inspections) are promoted to `## `. The result is a single H1 per page (the frontmatter title) with steps rendered at the next level down rather than buried under a duplicate-title H1. Bash-comment lines like `# TODO 4:` and `# Press Ctrl+C` inside fenced code blocks are untouched. Ch 3 banner correctness. While dropping the separator lines, the audit-missed fabricated startup banner in Ch 3 (matching the same shape of bug as the Ch 1 one the last commit fixed) was rewritten to match what the Compliance Worker actually prints. Build automation. A justfile at the repo root provides `just push`, `just pull`, `just init` (first-push helper that reminds you to commit the assigned ids), `just validate`, and `just diff` for the Instruqt CLI workflow.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
| run: | | ||
| if [ "${{ github.ref_name }}" = "main" ]; then | ||
| echo "extra=${{ env.IMAGE }}:latest" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "extra=${{ env.IMAGE }}:${{ github.ref_name }}" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
There was a problem hiding this comment.
Using variable interpolation ${{...}} with github context data in a run: step could allow an attacker to inject their own code into the runner. This would allow them to steal secrets and code. github context data can have arbitrary user input and should be treated as untrusted. Instead, use an intermediate environment variable with env: to store the data and use the environment variable in the run: script. Be sure to use double-quotes the environment variable, like this: "$ENVVAR".
🥳 Fixed in commit 81ee050 🥳
This commit follows up on `ec8c183` (which introduced the Solution tabs) by working through a full audit of the eight chapter assignment files for consistency, attendee discoverability, and renderer behavior. Solution tabs. The six tabs added in the prior commit lacked `id:` fields and sat at the end of each chapter's tab list, after the Temporal UI service tab. Each now has a stable 12-character id (`cjoljjm4x5i1`, `ww0fsdf18zxw`, `azh4d9gf2did`, `lmldoarsfqyc`, `hhmx3u77tul9`, `mxlwpnohrz8r`) so subsequent pushes update the same artifact rather than racing against a fresh assigned id. The tabs also moved to index 1, immediately after Code Editor, on the theory that two code-viewing surfaces belong next to each other. Every `(tab-N)` button reference in chapters 3-7 was rewritten to absorb the index shift. Admonition syntax. The prior commit introduced two GitHub-flavored `> [!NOTE]` callouts in Chapter 2 alongside plain `>` blockquotes elsewhere. This commit completes that conversion: every blockquote in all eight chapters now opens with `[!NOTE]`, `[!TIP]`, `[!WARNING]`, or `[!IMPORTANT]`. Choices follow intent: `TIP` for the new "Stuck? See Solution" callouts, troubleshooting tips, and "where to go next"; `WARNING` for footguns (Ch 2 missing decorator, Ch 8 dev-server failure); `IMPORTANT` for Ch 7 production take-aways; `NOTE` for the rest. Solution-tab discoverability. Chapters 2-7 each gained a `[!TIP]` near the start of "What you will do" reminding attendees the **Solution** tab exists. Chapters 1 and 8 instead got a `[!NOTE]` explaining why their layout differs (Ch 1's Code Editor is the finished monolith; Ch 8's is the finished Java implementation), so the asymmetry between chapters does not look like a missing tab. Knowledge checks. Chapter 1 already ended with a knowledge-check blockquote; chapters 2-8 now have parallel three-question blocks at the end of each chapter's wrap-up, all under `> [!NOTE]`. The questions are calibrated to the chapter's central concept (sync vs async, error types, validator semantics, and so on) rather than trivia. Smaller fixes. Ch 3 Step 6 referenced the Web UI without a `[button label="Temporal UI"]` link; that link now points at the correct tab index. Ch 7 softened "~90 seconds total" and "~20 seconds" to ranges with explanations, since those numbers depend on retry timing. Every challenge frontmatter now sets `enhanced_loading: false` to match `track.yml` rather than `null`. No changes needed. The Ch 3 and Ch 5 worker startup-banner snippets were re-verified against the corresponding `compliance/worker.py` files in `workshop-nexus-intro-code` and match exactly. Chapter titles were already consistent in their casing.
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.
This commit drops the initial Slidev presentation deck for the
workshop, documents the repo's architecture and slide-deck
conventions in `CLAUDE.md`, and lands a second editorial pass over
all nine Instruqt chapter assignments. Plus a small justfile safety
fix and an end-to-end polyglot solve script.
Slidev deck (new, `slides/`). The whole directory is new: a master
`slides.md` that imports per-chapter files from `slides/chapters/`,
the vendored Temporal theme at `slides/theme-temporal/` (footer text
and `WorkshopToc.vue` chapter list customized for this workshop), and
ten chapter files (`welcome`, `ch01-why-nexus`, `ch02-service-contract`,
`ch03-sync-handler`, `ch04-caller-workflow`, `ch05-async-operations`,
`ch06-updates`, `ch07-lifecycle`, `polyglot`, `wrap`). Every on-slide
bullet has a matching `**Build N**` entry in the speaker notes
following the convention; AhaSlides transition slides ("Quiz Time",
"Halftime!", "Reaction Time") carry scripted Lead-in / Lead-out lines
keyed to specific AhaSlides slide numbers. The deck builds cleanly
with `pnpm build`.
Workshop-register slide patterns (mirrors `tmp/Temporal 102 in Python`).
The deck adopts four canonical 102 patterns that were missing from the
initial draft: a single workshop-level `During this workshop, you will`
Outcomes slide (verb-led contract with the room, in `welcome.md`),
per-chapter `Review` slides on the consequential chapters (Ch01, Ch04,
Ch05, Ch06, Ch07), an `Essential Points (1)` through `Essential Points
(5)` synthesis sequence at the wrap, and a combined "Thank you for
your time and attention / We welcome your feedback" closing slide that
replaces a separate `Questions?` end slide. The thesis sentence "The
contract is the integration." is reasserted three times: welcome ("What
Is Nexus?"), Chapter 2 close ("Why Types Matter Here"), and `Essential
Points (5)`.
Workshop register on slide bodies, personality in notes. The slide
bodies stay declarative throughout: no first-person opinion ("I
believe"), no tag questions, no dramatic ellipsis, no SRE anecdotes,
no mock dialogue. Those flourishes belong in talks, not workshops, and
live in the `<!-- ... -->` speaker-notes blocks where they coach the
delivery without competing with the slide for the room's attention.
Brand rule: Temporal logo never tinted mint green. The vendored theme
had `.cover-logo` and `.end-logo` set to `var(--temporal-green)`, which
renders the Temporal plus mark in mint and violates Temporal's brand
standards (the mark must be white on dark or black on light; mint
green is reserved for accent text, links, and UI affordances, never
the logo itself). Both layout selectors now hard-code `color: #ffffff;`
with an inline brand-rule comment above them so a future editor does
not "fix" it back to the palette variable. The `TemporalLogo.vue`
component header was expanded with the same rule so it travels with
the component for any future layout that imports it. Other mint-green
uses (link colors, page numbers, TOC dots, blockquote borders) were
left alone; the rule is logo-specific.
CLAUDE.md (new, untracked). Captures the repo's three runtime surfaces
(Instruqt lab, Slidev deck, AhaSlides), the sandbox-image build flow,
the sparse-stage pattern in `setup-workshop` scripts, the load-bearing
nature of Instruqt-assigned `id:` and `tabs:` ids in YAML frontmatter,
and the slide-deck conventions described above. A new "Brand rules"
section codifies the logo-color rule above so any future session
rendering or editing the theme inherits it without needing to find
the inline CSS comment first. Calls out `tmp/` as the local-only
references directory holding `style.md` (the synthesis style guide,
which can overgeneralize) and the two source PPTX decks (`Temporal
102 in Python` and `Events are the Wrong Abstraction`) that are
canonical for any pattern decisions; the PPTX wins when they
disagree.
Instruqt assignment prose pass (chapters 1 through 8). Tightened
wording across every chapter, removed remaining forward references
("Chapter 5 adds them" -> "the next chapter adds them" or fully
inlined), and made several technical explanations more precise:
- Ch 1: reframed the monolith framing note to make explicit that the
visible-Activity coupling is the extreme form, while the more common
shape in production is two teams sharing a namespace and task queue
with no contract between them. Smoothed the TXN-B description so the
$10K threshold reads as the cause directly.
- Ch 2: unchanged in spirit; rewording for cadence.
- Ch 3: tightened the sync handler explanation; minor cleanup.
- Ch 4: expanded the "no caller-side retry policy" bullet to make the
retry-vs-timeout distinction explicit (Nexus owns retries of the
StartOperation, bounded by `schedule_to_close_timeout`; the policy is
built-in and not user-tunable; only the timeout envelope is). Added a
new `Nexus:` line example for the worker startup banner.
- Ch 5: small cleanup; `compliance-ch05-{txn_id}` workflow IDs
consistent.
- Ch 6: switched the `__init__` to `@workflow.init` with a typed
`request: ComplianceRequest` parameter and explained why (constructor
parameters are bound before message handlers run, so `_request` is
typed `ComplianceRequest` instead of `ComplianceRequest | None`).
Added the "Update rejection writes nothing to History" nuance to the
validator paragraph (no `Accepted`, no `Completed`, no `Rejected`
events). Added the `start_update(..., wait_for_stage=ACCEPTED)`
alternative as a follow-up to `execute_update`. Workflow IDs are now
`compliance-ch06-{txn_id}` and `payment-ch06-{txn_id}` to keep
per-chapter histories isolated for the lab.
- Ch 7: rewording for cadence; lifecycle scenario explanations
tightened.
- Ch 8: polyglot framing tightened; small clarifications.
Polyglot solve-workshop walks the full A/B/C path. The previous
solve script ran `payments.starter` once and exited, which left TXN-B
blocking on the Java handler's `wait_condition` and never produced the
finished-state output. The script now backgrounds `payments.starter`,
sleeps briefly, runs `payments.review_starter` to unblock TXN-B, then
waits on the starter to drain through TXN-C. The solve now exercises
the same flow attendees see in the live demo plus the Chapter 6 review
path against the Java handler.
Chapter 09 (`what-next`) updates. Replaced the generic Nexus tutorial
link with the specific Java sync tutorial URL plus the canonical
Python Nexus quickstart on the docs site. Expanded the sample-code
references to specific subdirectories per language (`hello_nexus/`,
`nexus_cancel/`, `nexus_multiple_args/`, `nexus_sync_operations/` on
the Python side; the Java equivalents). Replaced the em-dash list
separator with colon-led prose to match the no-em-dashes rule.
Added a `CLAUDE_HELP` HTML comment at the top of the chapter flagging
the release blocker that `temporalio/workshop-nexus-intro-code` is
currently empty (only `.gitignore` and `LICENSE`). The comment never
renders to attendees; it exists so a future Claude session sees the
unfinished prerequisite and surfaces it before the workshop ships.
justfile default recipe is now `@just --list`. Previously `just`
with no arguments ran `push`, which is destructive (it would push the
local `instruqt/` tree to Instruqt). Listing the recipes is the safer
default; pushing now requires the explicit `just push`.
Other small changes. `.gitignore` adds `.playwright-mcp/` so the
Playwright MCP server's local artifacts stay out of the tree.
`instruqt/track.yml` got a regenerated `checksum:` from the Instruqt
CLI tooling.
Ch 1 narrative restructure. The chapter now opens with the framing
slides (Two Teams, What Goes Wrong, The Shape You Probably Have,
Quick Poll), runs the monolith exercise (Exercise 1) BEFORE
introducing Nexus, then runs a "Where Are the Seams?" debrief slide
that surfaces what students just saw, and only then transitions into
the Nexus solution arc. The pedagogical principle: feel the pain
before being told the fix. Adult learners internalize architecture
problems they have just touched, not problems explained to them. The
lab assignment was already written for this placement; only the slide
order changed.
New slides in Ch 1.
- "Where Are the Seams?" — a debrief slide that reflects on what was
just observed in Exercise 1, with priming bullets for the deck
driver in case the room is quiet (Compliance code on the Payments
Worker, same default namespace + payments-processing task queue, no
boundary in Event History; deploy coupling, blast radius, mixed
PCI/KYC scope).
- "Two Operation Types" — explicit synchronous vs asynchronous
Operation distinction, set BEFORE Two Hard Limits so the room has
both words anchored before the constraint slide lands. Table format:
Behavior, Used for, Bounded by; lead-in line names that the
Operation is the one building block of the four with a choice.
- "Same Word, Three Different Things" — a vocabulary disambiguation
slide for "handler", which the docs use for three referents (a side,
a piece of code, a Worker). Workshop convention: "handler" for the
code, "implementer" for the side, "Worker" stays "Worker", "caller"
stays "caller." Speaker notes name the issue ("you're not crazy")
and give the room a portable habit ("substitute 'implementer' when
the docs say 'handler' for the role; after a week you won't notice
you're doing it").
- "From Weld to Contract" — the Nexus introductory slide, renamed
from "What Nexus Is, In One Sentence" to ground the welding/seam
metaphor that runs through the chapter. Sentence is now: "A Nexus
call is a way of invoking a typed Operation behind a contract, with
durable delivery. Think durable RPC." Reviewed against the docs MCP:
accurate today (caller is a Workflow, per Python SDK README) and
forward-compatible (the slide says "a way of invoking" rather than
"a Workflow invoking" so it stays accurate when non-Workflow callers
ship per the GA roadmap).
- "A Preview of the Destination" — the Topology Sandbox preview,
moved into Ch 1 from the welcome chapter and reframed as a
destination tease that lands AFTER the Nexus intro arc instead of
as an early-workshop logistical beat.
Two Hard Limits corrected. The previous framing ("Sync handlers must
respond within 10 seconds") was incorrect per Cloud limits and
nexus/operations docs: the 10-second per-attempt deadline applies to
BOTH sync AND async handlers. What differs is the work that has to
fit in the window. Sync must produce the full result inside it; async
only has to start a Workflow (`start_workflow` returns in
milliseconds), with the resulting Workflow then running up to
schedule_to_close (60-day cap on Cloud). The slide now reflects this,
and the Review slide at the chapter close was updated to match.
Vocabulary disambiguation across the deck. The Temporal docs use
"handler" for three different referents (a team or namespace, a
function or class, a Worker process), which is internally consistent
but causes referent-shift confusion sentence to sentence. The
workshop now adopts:
- "handler" = the code only (a function or class decorated with
`@sync_operation` or `@workflow_run_operation`).
- "implementer" = the side, the team, the role.
- "Worker" stays "Worker." Already its own well-known concept.
- "caller" stays "caller." The docs only use that word one way.
Sweep applied across ch03, ch05, ch06, ch07: 11 instances of
"handler-side" / "handler side" replaced with "implementer-side" /
"implementer side". Code-level usages of "handler" (sync handler,
async handler, handler Worker, handler Workflow, decorator names) are
kept because they match SDK and doc canon.
Welcome chapter trimmed. Removed "What Is Nexus?" (the definition now
lives only in Ch 1's "From Weld to Contract", so the welcome chapter
doesn't blow the punchline) and "A Preview, Before We Begin" (moved
into Ch 1 and reframed). About Me line condensed. Three Environments
slide adds an inline AhaSlides QR code (asset added to
`slides/public/ahaslides-qrcode.png`) so the room can scan to join.
The Agenda table is now a 7-row schedule with scoped styling (smaller
font, tighter padding) so it fits the slide.
Schedule alignment across all four artifacts. The workshop runs 9:00
to 12:30 with a hard-locked 11:00 to 11:30 break. To fit those
constraints, Ch 5 (Async Operations) moves to BEFORE the break
instead of after. Updated:
- `slides/chapters/welcome.md` Agenda table.
- `course-plan.md` activity timing table (Ch 5 row reordered).
- `aha.md` "Trigger pattern" prose (Ch 1 deviation called out
explicitly), mermaid flowchart restructured to show Ch 5
lecture/quiz/lab landing before halftime, "Halftime and break"
section consolidated.
- `CLAUDE.md` ordering note rewritten: now reads as "Ch 1 is
intentionally asymmetric" instead of "course-plan and aha disagree."
AhaSlides deck physically reordered. Used the AhaSlides MCP to move
slides 22-25 (Ch 5 questions) before slide 19 (halftime leaderboard)
so the deck ordering matches the new chapter sequence. Final order:
Ch 4 closes (slides 17-18), Ch 5 questions (19-22), halftime
leaderboard (23), break-time pulse and Q&A parking lot (24-25), Ch 6
onward (26+).
Section-divider title slides removed. Each chapter previously opened
with a TOC slide followed by a section-divider title slide (e.g., `#
01 / Why Nexus`, `# 02 / The Service Contract`). The TOC slide already
highlights the current chapter, so the additional section-divider
title was redundant. Removed across ch01 through ch07, polyglot, and
wrap (9 slides total).
Wrap chapter additions. New "What's Next for Nexus" slide inserted
between "Patterns We Didn't Cover" and "Where to Go Next". Lists
roadmap items pulled from the Nexus GA announcement and the Public
Preview blog: non-Workflow callers (bash, service, app), contract-
first development with `nexus-rpc-gen`, per-caller rate limiting plus
fine-grained authorization, enhanced routing rules. Closing v-click
ties back to the "durable RPC" framing from Ch 1: "Today's Workflow-
to-Workflow case is one application of a broader durable-RPC story.
The platform is leaning in."
Theme typography brought to PPT-equivalent. Font sizes now mirror the
canonical `Temporal 102 in Python` deck:
- h1 (slide title) = 3rem (48pt PPT equivalent).
- h2 = 2.2rem, h3 = 1.7rem (proportional).
- p, li, base = 1.375rem (22pt).
- code blocks = 1.375rem (22pt); inline code = 1.2rem.
Footer raised from 48px to 18px from canvas bottom via `margin-
bottom: -1.875rem` on `.temporal-footer`, leaving the content's
lower-third protection intact (the layout's `padding-bottom: 3rem`
still constrains where content can go; only the footer extends past
it). Patterns slide punchline ("None of these draw a line between
teams.") styled with a scoped class: centered, larger font, mint
green for both regular and bold text. Agenda slide has scoped
table styling (smaller font, tighter cell padding) so 7 rows fit
comfortably.
Em-dash sweep. The user's no-em-dash rule applies to every written
output for this project (memory file
`feedback-no-em-dashes.md`). Em-dashes were introduced in earlier
sessions across speaker notes and prose; this commit removes them and
replaces with periods, commas, colons, semicolons, or parentheticals
as appropriate.
GitHub Actions image build cleanup. Removed the `repository_dispatch`
trigger that auto-republished the sandbox image when the code repo
notified this repo. The build now triggers on push to `main` when
`docker/**` or the workflow itself changes, and is also manually
triggerable via `workflow_dispatch` from the Actions UI (with an
optional `code_ref` input). Republishing after a code-repo change is
now a deliberate manual click.
Other small changes. `slides/slides.md` dropped 20 lines of unused
intermediary headmatter. `instruqt/track.yml` got a regenerated
`checksum:` from the Instruqt CLI tooling. New untracked directory
`slides/public/` holds the AhaSlides QR code asset referenced from the
Three Environments slide.
Multi-session sweep. The deck got new slides and reorganized teaching
notes, the schedule moved from one 30-minute break to two 15-minute
breaks, the Slidev exercise layout grew a real countdown timer, the
Instruqt labs absorbed Michael Haynie's QA feedback, and the repo got
a top-level README.
## Instruqt: Michael Haynie's lab review
Michael walked the labs end to end and flagged a punch list. All
addressed in this commit:
- **Ch 1**: KYC and AML acronyms expanded to "KYC (Know Your
Customer)" and "AML (Anti-Money Laundering)" on first appearance.
- **Ch 2**: corrected the misleading claim that only `endpoint get`
surfaces the Markdown description (`endpoint list` shows it too);
fixed the left-nav tab label from "Nexus Endpoints" to "Nexus" to
match the dev-server UI as deployed.
- **Ch 3**: removed the entire "Confirm both Workers are healthy"
step. It told learners to click a Workers entry in the left
navigation that does not exist on the workshop's dev-server build.
- **Ch 4**: reordered TODO 4a to land before TODO 4b in the lab so
the natural reading order matches the apply order; dropped the
false promise that the worker startup banner gains a `Nexus:`
line. The deployed exercise's print statement is hardcoded
monolith-style and the lab can't promise it changes.
- **Ch 5**: clarified that the Worker startup banner is intentionally
minimal in this chapter (no `Registered:` line) so the absence is
not a bug to chase; rewrote the optional durability test to stop
the Compliance Worker BEFORE running the starter rather than
trying to Ctrl-C it inside a 2-second window. The new shape: kill
the Worker, run the starter (it blocks at NexusOperationScheduled
with no Started event), restart the Worker, watch it pick up. The
durability point lands without the timing pressure.
- **Ch 7**: pivoted Scenario B's inspection to read Event History at
the user's own pace (`temporal workflow show`) as the primary
path, with the live `BackingOff` watch demoted to optional. The
20-second window the starter held open before terminating was too
tight for someone reading carefully.
- **Ch 9**: replaced the broken Yes/No survey (which required
selecting BOTH boxes to advance because of `solution: [0, 1]`)
with a single-answer reflection quiz on the workshop's central
thesis ("typed Service contract plus a Nexus Endpoint"). The
survey signal moves entirely off Instruqt to the post-workshop
feedback link on the closing slide.
The Ch 5 "missing imports" bug Michael hit is fixed in the companion
`workshop-nexus-intro-code` repo's working tree (uncommitted there as
of this session); landing it requires committing in that repo and
rebuilding the sandbox image.
## Instruqt: feedback collection removed from the lab
Instruqt's in-lab feedback recap and feedback tab are off. Mason runs
a separate post-workshop survey via the QR + URL on the wrap deck's
closing slide, so the Instruqt-side prompts were redundant.
- `instruqt/track.yml`: `feedback_recap_enabled` and
`feedback_tab_enabled` flipped from `true` to `false`.
- `instruqt/09-what-next/assignment.md`: removed the callout
pointing at the Feedback tab.
The community-forum reference in Ch 9 ("long-form questions, design
feedback, and searchable history") describes the forum's purpose and
stays.
## Schedule restructure: two 15-minute breaks
Schedule moves from a single 30-minute break at 11:00 to two
15-minute breaks (9:45-10:00 and 11:15-11:30). The day now reads as
three blocks:
- **Block 1 (45 min)**: Welcome, Ch 1, Ch 2. Set up the problem,
define the contract.
- **Block 2 (75 min)**: Ch 3, Ch 4, Ch 5. Build the integration end
to end, sync handler through the caller swap into async.
- **Block 3 (60 min)**: Ch 6, Ch 7, Polyglot, Wrap. Human-in-the-loop,
lifecycle control, polyglot demo, close.
Halftime + leaderboard now lands at 11:15-11:30, after Ch 5, instead
of replacing the break. Updated:
- `course-plan.md`: activity timing table reordered, "three blocks"
paragraph added below totals.
- `slides/chapters/welcome.md`: Agenda table rewritten to match the
new block structure.
- `aha.md`: prose adjustments are minimal here; AhaSlides ordering
was already locked in the prior commit.
## Slidev: countdown timer in `exercise.vue`
The exercise layout grew from a static "N min" chip into a real
countdown timer.
- MM:SS countdown.
- Play / Pause toggle that morphs based on state. Idle starts the
timer; running pauses; paused resumes; expired resets and starts.
- Restart button always resets to full duration and starts running.
- State persists via `localStorage` keyed by `(heading, minutes)` so
the timer survives slide navigation and stays in sync between
presenter and audience views.
- Storage key namespace: `nexus-workshop:timer:<heading>:<minutes>`.
The timer is wall-clock based (stores `endsAt` while running, not a
decrementing counter), so a slide that sits unmounted for 90 seconds
returns with the right remaining time.
## Slidev: chapter content changes
Heavy rework across all seven content chapters and the wrap. Pattern
of the changes:
- **Headlines refactored to define by behavior, not by Python form.**
Ch 3's "What Is a Sync Nexus Handler?" now opens with what the
handler does (run and return inline within the deadline) and
demotes the `@sync_operation` reference to a bullet. Ch 5's
"Defining an Async Handler" replaces the decorator-named slide
title for the same reason. Mirrors Ch 2's "What Is a Nexus
Service?" mold.
- **Teaching notes split out from spoken script.** Speaker notes are
now structured as: spoken script with `**Build N**` markers up
top, then a `## Teaching notes` block below for stage direction,
doc citations, anecdotal anchors that stay verbal, and reasons a
given build exists. Applied across every chapter file.
- **New "When to Use a Sync Handler" slide in Ch 3.** Implements the
PM-call guidance: sync is for fast, reliable handoffs (forwarding
to a workflow, in-process compute, reliable downstream Temporal
infrastructure), not for arbitrary external HTTP. Names the
circuit-breaker scope (per caller-Namespace, Endpoint pair) and
why rate-limited APIs trip it. The workshop's `check_compliance`
is anchored as the reliable in-process case explicitly.
- **New "What's Different on Temporal Cloud" slide in the wrap.**
Cloud-vs-self-hosted differences land as five bullets:
per-Endpoint allowlist, mTLS Envoy mesh + audit logs,
account-scoped Endpoints, HA Namespaces and cross-region routing,
production limits / Worker tuning. Frame: the contract is
portable; the Cloud differentiators sit on the operator surface.
- **New "Meet the Teams" slide in Ch 1.** Business framing
(Payments processes transactions; Compliance assesses regulatory
risk into LOW / MEDIUM / HIGH) before the chapter's pain
enumeration. The structural picture got the room the topology;
this slide gives them the stakes.
- **Standalone activities added to wrap close.** New bullet under
"Patterns We Didn't Cover": standalone activities, GA-imminent on
Temporal Cloud, the right tool for unreliable external HTTP.
Co-launch with Coinbase 2026-05-06; customer name lives in
Teaching notes only, never on the slide.
- **Cancellation table tightened in Ch 7.** Removed the
decision-tree mermaid (overlapped with the table); compressed
table cells; merged the wire-format aside into a v-click; surfaced
"sync Operations cannot be cancelled" as its own v-click.
- **`# Four Ways Off the Happy Path`** replaces Ch 7's "What This
Chapter Teaches You to Recognize" headline. More direct, easier to
return to from the next slide.
- **Authority framing added in Ch 2.** The Service is owned by the
team that names it. Other teams open PRs against it; the owning
team has write access. Compliance writes the contract, registers
the Endpoint, and decides who's allowed to call. This frames the
per-Endpoint allowlist that lands later.
- **AhaSlides URL updated everywhere from O8RSE to NEXUSWS.**
Final-standings slide and reflection slide both point at the new
shortcode.
- **Closing slide gains the feedback QR.** `exit-survey-feedack.png`
added to `slides/public/`; bottom-right positioning via scoped
`<style>`. URL is `t.mp/replay26-ws-feedback`. Replaced the prior
AhaSlides URL on the close.
## CLAUDE.md additions
- New row in "What lives where" pointing at `slides/DEPLOY.md` (VPS
hosting guide; previously undocumented in the index).
- New section "Vocabulary convention: handler vs implementer"
documenting the workshop's disambiguation of the docs' three uses
of "handler" (side, code, Worker process). Specifies which
phrasings belong to the role (sweep to "implementer") and which
belong to the code (keep "handler"). Pairs with the Ch 1 "Same
Word, Three Different Things" slide.
- Slide-deck conventions block expanded: per-slide `<style>` blocks
beat frontmatter `class:` overrides for theme-font-size overrides;
chapters open with `layout: toc` only and never re-add section
dividers; PPT-equivalent font sizes documented with the conversion
rule (Slidev's 980px canvas vs PPT 16:9's 960pt).
- Thesis-sentence reassertion location updated to "From Weld to
Contract" (was "What Nexus Is, In One Sentence").
## Top-level README
New `README.md` at the repo root. Public-facing entry point that
explains:
- What the workshop is, who it's for.
- The three runtime surfaces (Slidev deck, Instruqt lab, AhaSlides),
with a Mermaid flowchart of how they hand off.
- Repo layout table with clickable paths.
- Quick-start commands (Instruqt CLI recipes, Slidev `pnpm` scripts,
PDF export).
- Pointer to `slides/DEPLOY.md` for live presenter-follow setup.
- Sandbox-image build flow (CI on `docker/**` push, manual republish
via `workflow_dispatch`).
- Pointer to the companion `workshop-nexus-intro-code` repo.
- Pointer to `CLAUDE.md` as the canonical authoring guide.
Deliberately does not duplicate `CLAUDE.md` content. CLAUDE.md is the
deep authoring/conventions manual; README is the entry point.
## Other small changes
- `aha.md`: graded-quiz prompts gained explicit correct-answer and
distractor labels for slides 9, 15, and 29; the Match-pairs
prompt for cancellation types now spells out the four pairings
inline rather than relying on the AhaSlides UI alone.
- `slides/public/exit-survey-feedack.png`: new asset for the closing
feedback QR.
prasek
left a comment
There was a problem hiding this comment.
overall lgtm, dropped some comments/suggestions
|
|
||
| <v-clicks> | ||
|
|
||
| - **Shared blast radius.** A bug in `check_compliance` takes down `execute_payment`. |
There was a problem hiding this comment.
| - **Shared blast radius.** A bug in `check_compliance` takes down `execute_payment`. | |
| - **Shared blast radius.** A bug in `check_compliance` takes down `execute_payment`. | |
| - **Overly permissive security.** Both teams have full access to everything in the monolithic namespace. |
|
|
||
| <v-click> | ||
|
|
||
| A Nexus **Service** is that contract, expressed in your SDK's native types. |
There was a problem hiding this comment.
| A Nexus **Service** is that contract, expressed in your SDK's native types. | |
| A Nexus **Service** is that contract, expressed in your SDK's native types (with JSON serialization or proto defs for polyglot environments). |
We mention Polyglot later but should really put folks at ease that it's not just native types (and single language) but we do support polyglot - just like the rest of Temporal does with the same data converters
|
|
||
| <v-click> | ||
|
|
||
| **Avoid for arbitrary external HTTP.** Rate limits, timeouts, and 5xx trip the circuit breaker fast. |
There was a problem hiding this comment.
| **Avoid for arbitrary external HTTP.** Rate limits, timeouts, and 5xx trip the circuit breaker fast. | |
| **Back with a Workflow or Standalone Activity for arbitrary external HTTP.** Rate limits, timeouts, and 5xx can trip the Nexus circuit breaker fast so handoff to a durable backing primitive. |
| - **What happens.** | ||
| - New Operations get `State: Blocked`. After 60s, one probe decides close or re-open. | ||
| - **Why a trip is bad.** | ||
| - Every caller targeting that Endpoint freezes for at least a minute. |
There was a problem hiding this comment.
| - Every caller targeting that Endpoint freezes for at least a minute. | |
| - Each Nexus caller-destination pair trips independently, so specific callers can freeze for a minute or more if the circuit breaker is not considered. |
|
|
||
| # Spotting a Circuit-Breaker Trip | ||
|
|
||
| When the breaker opens, here's what it looks like in production. |
There was a problem hiding this comment.
| When the breaker opens, here's what it looks like in production. | |
| When the breaker opens for a caller-destination pair, here's what it looks like in production. |
|
|
||
| - Cross-team Temporal integration needs cross-team Nexus Endpoints. **Namespaces become tenancy boundaries with real teeth.** | ||
| - A Nexus **Service** is a typed Python class both teams import. **Operations** are the typed methods on it. | ||
| - An **Endpoint** is a routing entry the operator creates with the Temporal CLI. Caller code names only the Endpoint. |
There was a problem hiding this comment.
| - An **Endpoint** is a routing entry the operator creates with the Temporal CLI. Caller code names only the Endpoint. | |
| - An **Endpoint** is a reverse proxy with a routing entry the operator creates with the Temporal CLI. Caller code names only the Endpoint. |
| - **Synchronous handlers** run inline on the handler Worker, return a result directly, and must respond within a **10-second** per-request deadline. | ||
| - **Asynchronous handlers** return a `WorkflowHandle` to a workflow that produces the result. Up to **60 days** on Temporal Cloud. | ||
| - Choose sync when the work fits comfortably under five seconds. Choose async for everything else, especially anything that needs cancellation. | ||
| - Set all three timeouts (`schedule_to_close`, `schedule_to_start`, `start_to_close`) on every async caller. Use `WorkflowIDConflictPolicy.USE_EXISTING` for idempotent retries. |
There was a problem hiding this comment.
Do you really need to set all 3 timeouts, or would just schedule_to_close be sufficient in most cases?
| <v-clicks> | ||
|
|
||
| - **Synchronous handlers** run inline on the handler Worker, return a result directly, and must respond within a **10-second** per-request deadline. | ||
| - **Asynchronous handlers** return a `WorkflowHandle` to a workflow that produces the result. Up to **60 days** on Temporal Cloud. |
There was a problem hiding this comment.
| - **Asynchronous handlers** return a `WorkflowHandle` to a workflow that produces the result. Up to **60 days** on Temporal Cloud. | |
| - **Asynchronous handlers** return a handle to obtain the result, cancel, and otherwise manage the async Operation. Up to **60 days** on Temporal Cloud. |
We'll be supporting different types of async handlers in the future, not just WorkflowHandle, but for async updates, and generic async Nexus ops that are manually completed.
Co-authored-by: Phil Prasek <prasek@gmail.com>
Co-authored-by: Phil Prasek <prasek@gmail.com>
Co-authored-by: Phil Prasek <prasek@gmail.com>
Co-authored-by: Phil Prasek <prasek@gmail.com>
This commit picks up the non-verbatim portion of Phil Prasek's review on PR #1. The verbatim-accept suggestions (Durable RPC rename, async-match correction, INTERNAL parenthetical, evaluate link) already landed in the four prior commits via GitHub's "Apply suggestion" button. ## Reworded accepts Three of Phil's suggestions were accepted in spirit but reworded to fit the deck's slide register and the existing v-click rhythm. - **Sync-handler external HTTP framing (ch03).** The "Avoid for arbitrary external HTTP" anti-pattern bullet is now Phil's prescriptive form: "For arbitrary external HTTP, back with a Workflow or Standalone Activity." Build 4 speaker note updated to match. The slide now points the room at the right tool instead of just naming the wrong one. - **Endpoint reframed as "reverse proxy with a routing entry."** Phil pointed out that "routing rule" understates what an Endpoint is; it is a reverse proxy in the system architecture. Applied consistently across ch03's "What Is a Nexus Endpoint?" slide and speaker note, ch03's "Creating the Endpoint" slide and speaker note, and the matching Essential Points (1) bullet on the wrap. The DNS-entry mental model stays as the accessible analogy. - **Async handlers stay generic on the wrap (Essential Points 2).** Replaced the specific `WorkflowHandle` reference with Phil's "a handle to obtain the result, cancel, and otherwise manage the async Operation." A new `## Teaching notes` block on the slide explains why the wrap stays abstract (more async handler shapes are on the Nexus roadmap: async Updates, manually-completed async ops) while ch04 and ch05 keep concrete `WorkflowHandle` framing. ## Speaker-note adds Three of Phil's on-slide suggestions were rejected on the slide body but added as verbal callouts in speaker notes. The on-slide claims stay tight; Phil's substance lands aloud. - **ch02 polyglot reassurance.** Build 4 sub-bullet on "What Is a Nexus Service?" now disambiguates "native types" from single-language: JSON wire format, optional proto defs, same data converters as the rest of Temporal. Polyglot is first-class. - **ch03 trap-everything edge case.** "If asked" footnote under Build 5 of "When the Workers Aren't Running": a handler that catches every exception and returns a non-retryable error stays out of breaker territory even when it is busted. Pick error types deliberately. Teaching note credits Phil and warns not to introduce unprompted because it muddies the slide's main thesis ("watch your Worker fleet"). - **ch06 sync-only Nexus Updates today.** Build 5 sub-bullet on "Workflow Updates in 60 Seconds" anchors the actual 10s ceiling and the sync-only-today reality (async Nexus Updates with their own callback semantics for arbitrary duration are on the roadmap, not GA). Title stays unchanged; new Teaching note explains the "60 Seconds" is a pacing meta-phrase, not a duration claim. ## Roadmap-slide sharpening `wrap.md` "What's Next for Nexus" Build 5 speaker note now uses Phil's "single routing rule today" framing explicitly. Names the multi-rule capability in flight (traffic-split, canary, per-caller routing without standing up a new Endpoint). Replaces the previous "one Endpoint maps to one (Namespace, Task Queue)" wording, which was correct but lands less cleanly once the multi-rule capability ships. ## Timeout narrow fix Phil questioned whether the wrap's "Set all three timeouts" guidance is actually how Temporal recommends configuring async Nexus callers. He is right, and the docs MCP corroborates: `docs.temporal.io/nexus/operations#timeouts` treats `schedule_to_close_timeout` as the umbrella with retries inside; `schedule_to_start` and `start_to_close` are explicitly opt-in ("if not set or zero, no timeout is enforced") and require Temporal Server 1.31.0 or later, flagged experimental in the Go SDK. - **wrap.md Essential Points (2).** Bullet rewritten from "Set all three timeouts" to "Set `schedule_to_close_timeout` on every async caller. `schedule_to_start` and `start_to_close` are situational." Build 4 speaker note expanded with rationale sub-bullets explaining what schedule_to_close bounds and when to reach for the other two (known queue-pickup ceiling, per-attempt cap distinct from total time). - **ch05 slide title.** "Three Timeouts You'll Actually Set" renamed to "Three Timeouts You May Set." Slide body still teaches all three (the room needs to know what each is), but the title now signals optionality and lines up with the wrap's framing. - **ch05 exercise TODO 9 left alone** by design. The exercise sets all three so attendees see them in action; the slide title and the wrap make clear that production usually only sets `schedule_to_close`. ## Rejected on-slide Documented for the record; no edits in this commit: - **PR #8 (ch01).** Adding "Overly permissive security" as a fifth pain bullet on "What Goes Wrong as Teams Grow" pre-empts ch03's Cloud allowlist punchline (which Phil himself elevated as the key takeaway in his earlier PM-call guidance). - **PR #10 (ch03:124).** Per-pair scope is already established three builds earlier on the same Circuit Breaker slide; the "Why a trip is bad" beat is meant to land impact, not re-explain scope. - **PR #14 (ch07:273).** Per-pair scope reminder on the diagnostic slide is saturated; the room has heard it four times by ch07. ## Files modified - `slides/chapters/ch02-service-contract.md` - `slides/chapters/ch03-sync-handler.md` - `slides/chapters/ch05-async-operations.md` - `slides/chapters/ch06-updates.md` - `slides/chapters/wrap.md`
No description provided.