Fix the rollback in an account signup saga

Review the AI's codeEasy10 min

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 is step|outcome|undo: the step name, ok if 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 log compensate:<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 commit at the end. An empty list logs only commit.

Examples

provision_with_compensation(step_lines: list[str]) -> list[str]
Example 1
Inputprovision_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
Inputprovision_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"]