Fix the rollback in an account signup saga
Your task
Signup creates a user, sets up billing and sends a welcome email. The first version ran all three at once with Promise.all, so when billing failed, the user row stayed behind and the email still went out. The new version runs the steps in order and undoes the finished ones when a step fails. This pattern is called a saga, and each undo is a compensating action.
An assistant wrote provision_with_compensation(step_lines), which works out what runs. It is in the editor. It has a bug. Find it and fix it.
Input and output:
step_lines: the steps in the order they run. Each isstep|outcome|undo: the step name,okif it succeeds, and the action that undoes it. An empty undo means the step cannot be undone, like a sent email.- Return the action log, a list of strings.
Rules the tests check:
- Split a line on
|. Skip it, logging nothing, unless it has exactly 3 parts and the step name is not empty. - Every step that is not skipped logs
run:<step>. - A step succeeds only when its outcome is exactly
ok. Any other outcome is a failure. - At the first failure, log
fail:<step>. Then logcompensate:<undo>for each earlier successful step, newest first, skipping steps whose undo is empty. The failed step's own undo is not run. Stop there: later lines are not read. - If no step fails, log
commitat the end. An empty list logs onlycommit.
Examples
provision_with_compensation(step_lines: list[str]) -> list[str]Example 1
Input
provision_with_compensation(["create_user|ok|delete_user", "create_billing|ok|void_billing", "send_email|ok|"])Output
["run:create_user", "run:create_billing", "run:send_email", "commit"]Example 2
Input
provision_with_compensation(["create_user|ok|delete_user", "create_billing|fail|void_billing", "send_email|ok|"])Output
["run:create_user", "run:create_billing", "fail:create_billing", "compensate:delete_user"]