Story: Give the workflow component a fixture it can run against itself
Table of Contents
This page documents a story in Sprint 26. It captures the goal, current status, acceptance criteria, and the tasks that compose it.
1. Goal
The workflow component is driven from ores.shell, against the live fleet and with no other component's data: the fixture runs the engine against itself, the engine acts across tenants, and its start, dispatch, success, warning, failure, compensation and recovery paths are each reachable and each asserted. The identity workflow and the commands that drive it split to Add the identity workflow and the commands that drive it at the sprint 26 close on 2026-10-05.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent sprint | Sprint 26 |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-10-05 |
On 2026-10-05, at the sprint 26 close, this story was reworded to the fixture and the cross-tenant engine it delivered and closed DONE. The task Add the identity workflow and the commands that drive it moved to Add the identity workflow and the commands that drive it.
3. Acceptance
- The workflow component has a fixture it can run against itself, so the engine is drivable and assertable from ores.shell without another component's data.
- The engine acts across tenants: a tenant's recovery re-dispatches its in-progress instances and no other tenant's.
4. Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Finish the workflow fixture | DONE | 2026-09-26 | 2026-09-27 | Task for: Exercise the workflow engine end to end |
| Make the workflow engine act across tenants | DONE | 2026-09-27 | 2026-09-27 | Task for: Exercise the workflow engine end to end |
5. Decisions
5.1. A script asserts what a run ends in; a test covers what a script cannot drive
The acceptance asks for every engine path to be asserted. Six of the nine identity configurations are scripts, because a script can start a run, name it, and wait for the terminal state it expects.
Three paths cannot be driven that way, and the reason is the shell's, not the
engine's: a start the engine refuses leaves nothing to wait on, recovery needs
a service restart mid-run, and a duplicate completion cannot be produced from
outside the engine at all. Those are covered by integration tests in
ores.workflow.core.tests, which call the handlers directly with the real
store and bus either side of them.
The two refusal cases assert nothing happens, so each carries its own control: the same call with a type that does resolve, in the same fixture, must create a run. Without that, a harness that started nothing at all would pass.
5.2. The fixture runs in the test tenant, the state ids come from the system tenant
Engine integration tests write their rows to the test tenant, so a case cannot see or disturb another environment's data. The FSM state ids are dq's seed data, which lives in the system tenant, and a state id carries no foreign key to a machine, so the two halves do not have to agree on a tenant.
5.3. Recovery is tenant-wide
recover_in_progress re-dispatches every instance its tenant has in progress,
not just the caller's. The recovery case proved it by accident: counting the
commands on the subject counted the instances the earlier cases had left
behind, so the result depended on the order the cases ran in. The case now
scopes its waits to its own instance id.