Review a repair¶
When a run stops because the application changed, a repair proposes a new version of the workflow. Before the runner tests it, a person reviews what changed. You can do that review in Cloud instead of at the runner. Cloud only records the decision; the runner's own steps still decide whether the repair is used. See Handle a halt for the full sequence.
1. Send the candidate to Cloud¶
On the runner, sign in with an ingest token once (openadapt flow login).
Then send a registered repair candidate with the engine's Python API:
from openadapt_flow.repair.cloud_review import propose_to_cloud
from openadapt_flow.repair.lifecycle import RepairStore
store = RepairStore("repair-store") # the --store the repair commands use
candidate = store.load_candidate("<candidate id>")
result = propose_to_cloud(candidate, workflow_id="<Cloud workflow id>")
print(result["review_url"])
What Cloud receives is digests only: for each changed step, the field and the SHA-256 before and after; the failure fingerprints; and the digests of the old and new bundle. No file path, screen text, or field value leaves the runner. A change counts as consequential unless every changed step is marked reversible.
2. Decide in Cloud¶
Open Repairs at /dashboard/repairs. Each candidate shows the before and
after fingerprints for each changed step, why the run stopped, and the bundle
digests. An owner or admin chooses:
- Approve for testing: the runner may now run its replay and fault tests on this version.
- Reject: the workflow keeps its current version and keeps stopping at that step.
Approving a change to how the record is identified, or to a step that saves data, needs an extra confirmation. A decision is final, and it is bound to the exact digests the reviewer saw. Only a person can decide; Cloud refuses a decision from a model.
3. Apply the decision on the runner¶
The runner reads decided candidates from GET /api/repairs/decisions with
its ingest token and applies each one:
from openadapt_flow.repair.cloud_review import apply_cloud_decision
apply_cloud_decision(store, decision)
An approval counts as the diff review (candidate → reviewed). A rejection
rejects the candidate. A decision made for different bundle bytes is refused.
The replay campaign, the fault campaign, the final approval, staging, and the
canary still run on the runner: