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.

6. Out of scope

Emacs 29.3 (Org mode 9.6.15)