Pulling Work and Retiring a Tenant

Lesson 3 of 4

Prepare the Calls, Then Commit Together

Estimated time: 10 minutes

Prepare the calls, then commit together

An agent that calls several tools which each change something has no natural grouping. One call fails after two succeeded and the run stops with a state no part of the plan asked for, half applied and half not, with nothing recording which is which.

A prepare phase fixes this. It checks preconditions and takes a claim on each resource without mutating anything, so a failure here costs nothing and leaves nothing to undo. Only when every claim is held is the group ready.

Between the phases, write the decision to commit into a journal. That entry is what makes a crash survivable, because a run that dies after preparing and before committing otherwise leaves an outcome nobody can determine from the platform state.

def commit_group(claims, apply_call, reverse_call, journal):
    journal.record({"state": "prepared", "claims": [c["id"] for c in claims]})
    applied = []
    for claim in claims:
        if not apply_call(claim)["ok"]:
            for done in reversed(applied):
                reverse_call(done)
            return {"state": "reversed"}
        applied.append(claim)
    journal.record({"state": "committed"})
    return {"state": "committed"}

Apply all of the group or none, and a prepared run is later resolved by reading the journal.