Assignee Sources
Two ways to say who should approve something:
- Name them. The workflow already knows the principal. Simple, and it’s what the tutorial uses.
- Point at a group somewhere else. Membership is owned by another system and can change while your workflow is waiting. That’s an assignee source, refreshed by a signed change event.
Start with the first. Move to the second only when membership genuinely lives elsewhere.
Gate G4 — required implementation. The resolver API is current. The starter’s provider normalization is still being finished.
A pending step records the provider ID and the principal reference, and the engine compares both. The same text under a different provider is never a match.
For recipients you already know, this is all you need.
hooks.assignees.resolver('siam', { context, resolve }).
You give it a source reference; it returns who is in that group now. It runs at the refresh boundary — when a change event arrives — and never during replay. That separation is what keeps replay deterministic while still letting the answer change over time.
Four things to keep from every refresh: the source key, the source version, the signed event ID, and what happened to the step.
Two properties to rely on. A duplicate event must be harmless — you will get duplicates. And a changed source can change who is able to complete a step that is already pending, without touching any event that was already recorded.
The Day 1 vacation coverage exercise walks through exactly that.