Business

Writing a Conflict-Resolution Policy for Agent Actions

Antonio Evans11 min read

A split-screen control room where two agents face each other over a PAY card and a REFUND card, a numbered precedence ladder hangs on the wall.
Key points

Key points

  1. 1Write a precedence ladder (human approval, owner-assigned agent, role seniority, freshest observation) that every agent loads at start-up so collisions resolve the same way every time.
  2. 2Define per-field merge rules so two agents editing different fields never enter the ladder at all.
  3. 3For money-moving actions, enforce single-writer per account, reserve before commit, and two-phase commits with compensating actions.
  4. 4Keep a decision log that records which action won, which rule applied, and the inputs behind the verdict.

Why conflicts are an architecture problem

Conflict in a multi-agent system is not a defect. It is the predictable result of deploying agents with different objectives over shared resources and overlapping authority. One analysis of agentic systems says plainly that agents conflict because they are doing what they were built to do, and that conflict resolution must be designed into the architecture rather than improvised after deployment (Arion Research). The same source sorts conflicts into four types: goal conflicts (a sales agent discounting to close a deal versus a finance agent enforcing payment terms), resource conflicts (two agents drawing on one budget pool), policy conflicts (helpfulness versus compliance), and interpretation conflicts (one agent reads "urgent" as 24 hours, another as top priority).

That taxonomy matters because each type needs a different mechanism. Interpretations are settled by a shared glossary. Policy conflicts are settled by hard constraints that cannot be negotiated away. Goal and resource conflicts need the precedence ladder and per-field merge rules below.

The alternative patterns stop working at scale. The "schedule a meeting and hash it out" approach fails when agents make hundreds of decisions per hour, and the "escalate to a manager" pattern fails when agents run across dozens of workflows at once (Arion Research).

One useful pattern comes from robotics. When several agents each hold safety constraints, satisfying them pairwise does not guarantee the combination is safe, and agents can enter a "leaky corner" where no single action satisfies all constraints at once. The proposed fix is layered: a planner that avoids crowding, a prioritization step for the most urgent pairs, and a dedicated safety filter that issues the corrective action (Choi et al., arXiv). Translate that to business agents: route, prioritize, then apply a deterministic filter. The filter is your policy.

The precedence ladder every agent reads at start-up

The ladder is an ordered list. The first rule that matches decides. Every agent loads the same list, so two agents that collide produce the same winner regardless of which one noticed the collision first.

RankRuleBeatsTypical case
1Explicit human approval or overrideeverythingA manager approves a refund, a rep reopens a ticket
2Owner-assigned agentall agent-vs-agent rulesThe account's designated agent holds write authority
3Seniority by rolefreshnessA compliance agent outranks a marketing agent on customer data
4Freshest observation, with tie-breakersnothingTwo agents of equal rank write the same field
5Escalate to a human queuenothingNo rule matches, or a money threshold is crossed

Three notes on making the ladder work.

First, rank 3 names roles, not individuals, and the role list is versioned alongside the policy. "Compliance outranks marketing" is a rule you can test. "Ask Dave" is not.

Second, rank 4 needs a tie-breaker that does not depend on wall-clock timestamps, because clocks disagree across machines. Use a monotonic sequence number attached by the observation source, and if two sequence numbers are equal, fall through to rank 5. The accepted way to detect conflicts between two candidate claims is the standard interval overlap test, Start1 <= End2 AND Start2 <= End1 (SQLServerCentral). The same arithmetic applies when two agents try to claim one calendar slot or one payable invoice.

Third, rank 5 needs a named queue and a timeout. An escalation rule with no queue is a deadlock.

A minimal ladder file, loaded at start-up, looks like this:

policy_version: 7
ladder:
  - id: human_override
    when: action.source == "human"
    beats: all
  - id: owner_agent
    when: agent.id == resource.owner_agent_id
    beats: [role_seniority, freshness]
  - id: role_seniority
    order: [compliance, finance, support, sales, marketing]
  - id: freshness
    compare: observation.sequence_number
  - id: escalate
    queue: agent-conflicts
    timeout_minutes: 30

The point of the file is that it is data, not prompt text. Two agents reading the same file cannot disagree about the order.

Per-field merge rules: define most collisions away

The cheapest conflict is the one you define out of existence. Two agents editing different fields of the same record are not in conflict, and treating them as if they were is the most common source of needless escalations.

Sort every shared record into fields and assign each field a merge strategy:

Field typeMerge ruleExample
Scalar, single ownerLast write wins, owner onlyAccount tier
Scalar, competing writersHighest ladder rank winsDiscount rate on a quote
Set (tags, labels)UnionIssue labels
CounterSum, guarded by idempotency keyUsage credits
Append-only logConcatenate in sequence orderActivity timeline
Free textLadder winner; loser kept in a shadow fieldCRM notes
Money amountReserve, then two-phase commitInvoice payment

Two habits make this work. Keep the loser's value in a shadow field or the decision log rather than discarding it, because someone will ask why a note vanished. And make the merge functions total: every field gets a rule, including the ones nobody has fought over yet, because the field nobody fights over today is tomorrow's escalation.

The calendar world shows why visibility without blocking fails. Sharing a calendar lets you see events, but seeing is not blocking: a colleague's invite only checks the busy state of that one calendar, so a personal event does not stop a work meeting from landing on top of it (Chronock). The same failure appears with agents. An agent that reads a shared record and then writes it, with no reservation between the two steps, creates a race. Real-time two-way sync, where a slot is removed from availability the moment it is taken, is what closes the gap (Cal.com). In your own systems, the write path must claim the slot, not merely observe that it was free.

For interval-shaped fields (booked windows, service periods, validity ranges), accept a write only if it does not overlap an existing one, and reject it with the conflicting window attached so the agent can propose an alternative. That single constraint removes the whole double-booking class of conflicts before the ladder is consulted.

Money-moving rules that outrank everything else

Money is where a wrong resolution is expensive and hard to unwind. Treat money-moving actions as a separate class with their own hard rules, layered on top of the ladder.

One writer per account. Each money account has exactly one agent identity authorized to write, and the authorization is enforced at the account level, not in the prompt. Other agents submit intents to the writer. This removes account-level races rather than resolving them.

Reserve before you act. Before any commit, hold the amount so a second agent sees it as unavailable. An unguarded agent that retries on timeout can produce duplicates in a short burst that no fraud rule catches; reconciliation finds them the next morning, when the customer disputes every charge and the auditor asks who authorized the purchase (Formance). The reserve step is the difference between a queue and a race.

Two-phase commit with a compensating action. Phase one reserves and records intent. Phase two commits. If phase two fails, the compensating action releases the reservation and writes a reversal entry, and the retry reuses the same idempotency key so the second attempt cannot double-spend. Idempotency keys are the standard mechanism for making retried requests safe to repeat, which is why payment APIs document them as a first-class feature (Stripe). An API call is a defined request and response between software systems (AWS), so the key belongs in the request contract, not in the agent's memory.

An approval gate above a threshold you set. Pick the threshold from your own loss tolerance, not a vendor default. Four autonomy models give you a menu: a human confirms every transaction; the agent holds a scoped credential with per-transaction limits and no per-transaction sign-off; the agent holds a virtual card with network-enforced spend rules; the agent holds its own wallet (Formance). For most enterprises the first or second covers the bulk of volume, with the higher models reserved for tightly capped spend.

A decision log that records who won and why. Every money-moving action writes the action id, the idempotency key, the agent identity, the ladder rule that authorized it, the amount, the reservation id, the commit or reversal outcome, and the approver if a gate applied. Without it, an auditor's question has no answer.

A worked example makes the cost visible. An invoice agent and a treasury agent both act on the same 4,000 dollar payable. Treasury sees a cash buffer below target and wants to defer. Invoice sees a due date and wants to pay. Without reservations, both commits land and the vendor is paid twice. With the rules above: single writer means only the invoice agent can pay; the reserve step makes the 4,000 unavailable when treasury reads the account, so treasury's deferral becomes an intent rather than a write; the conflict goes to the ladder, where finance outranks sales and the deferral wins for the cycle. The decision log records both intents and the rule. Added cost: one reservation row and one log entry.

The same logic at the boundary, in code:

def pay(account_id, amount, idem_key, agent):
    assert agent.id == accounts[account_id].writer_id
    if not reserve(account_id, amount, idem_key):
        return conflict(rule="reserve_held", amount=amount)
    try:
        txn = commit(account_id, amount, idem_key)
    except CommitFailed:
        release(account_id, idem_key)
        log_reversal(idem_key, agent)
        raise
    log_decision(idem_key, agent, rule="owner_agent", amount=amount)
    return txn

Approvals, handoffs and the human in the loop

The human end of the ladder deserves its own design. A gate that stops work for hours is worse than no gate, because teams route around it.

Progressive trust is the pattern worth copying. A system can start in a confirmation mode where it proposes actions (a booking, a reschedule, an update) and waits for staff confirmation before anything writes to the system of record; once the team is satisfied, it switches to automatic sync (Elva). Applied generally: week one, every consequential write is proposed and approved. Week two, low-risk classes auto-commit and money stays gated. Record the mode and the date of each change in the policy file, because "who decided this agent could write directly" is a question that eventually arrives.

Handoffs need context, not just routing. When a voice agent transfers a caller, the receiving person should get the reason, the captured information and the cause of the handoff so the caller does not start over (VocalOps). Your agent-to-human escalation should carry the same package: the colliding actions, the ladder rule that failed to decide, the fields in dispute, and a proposed resolution. A human who receives "conflict on invoice 4471, finance wants defer, sales wants pay, here are both intents" resolves in seconds. A human who receives "agent needs help" starts from zero.

Capability boundaries belong in the policy too. Permission matrices that toggle each capability per channel, with separate settings for sensitive topics drafted and held for approval, are a practical way to keep the gate narrow (Elva). Translate that to your own channels: allow cancellation by phone but not by email if the identity signal is weaker there, and hold financial replies for approval rather than blocking every reply.

The decision log and the tests that prove the policy

The decision log turns a policy into something you can audit and improve. Record the timestamp, policy version, colliding action ids, winning action, the deciding ladder rule, any field-level merge rule, the human approver, and the outcome. Write it append-only, then review it on a schedule for two signals. Rule distribution tells you which rule does the real work; if 60 percent of resolutions come from one rule, the others are decoration, so tighten or delete them. Escalation rate tells you where the ladder is incomplete: each cluster of similar rank-5 escalations is a candidate new rule.

The log also supplies the numbers for the approval threshold. Pull the distribution of money amounts and the reversal rate per class, then set the threshold where expected error cost (amount times reversal frequency plus cleanup hours) exceeds the cost of one approval minute. That is a calculation you can defend, unlike a threshold copied from a blog post.

For teams running several agents across a line of business, policy design and operating discipline converge on the same questions: which agent owns which writes, what gets gated, and who reviews the log. That is the kind of setup Quanta Experts (https://quantaintelligence.ai/agents) fits, since each expert reads your context, does the work and hands back finished deliverables, including a draft policy and decision-log schema you can review.

A policy never tested against failure is a wish. Run these five tests against a staging copy of the ladder.

TestInjectPass condition
DeadlockTwo agents each wait on the other's reservationEscalation fires within the timeout
DuplicateSame idempotency key sent twiceOne commit, one logged replay
Clock skewEqual sequence numbers, skewed host clocksRank 5 escalation, no silent overwrite
Partial failurePhase two commit raises after reserveReservation released, reversal logged
Late humanApprover responds after the agent retriedRetry is a no-op, not a second action

The partial failure and duplicate tests matter most, because both produce money errors and both are preventable with the reserve and idempotency rules. The clock skew test catches the subtle bug where an agent wins on freshness because its host clock runs fast. Add one more: a sample set of thirty labeled conflicts that two agents must resolve identically. Divergence means the policy text is ambiguous, and the sample set becomes the regression suite for every future edit. If your agents speak through one API layer, those tests run across model providers without a new harness; that is how Quanta Inference (https://quantaintelligence.ai/inference) is arranged, with text, image, video, audio and embedding models behind one OpenAI-compatible key, prepaid and priced in US dollars.

Drafting the document itself

Put the policy in one versioned file with five sections in this order: scope (which resources and action classes it covers), the ladder, the per-field merge table, the money rules with thresholds and approvers, and the escalation and review process. Keep it short enough that a new engineer reads it in one sitting, and require a version bump for every change, logged with who approved it and why.

Two writing rules carry most of the quality. Every rule must be decidable by a machine from data it already has; "use judgment" is not a rule, it is an escalation with no queue. And every rule needs a named counterexample in the document, a case it deliberately does not cover, because the boundary is where reviewers find the gaps.

The policy is finished when three people can independently resolve the same ten conflicts using only the document and reach the same answers. Until then it is a draft, and no money-moving agent should run against it.

FAQ

FAQ

Why can't each agent just check before it writes?

A check-then-write is a race: two agents can both read a free slot and both write it. The fix is to claim the slot atomically with a reservation, which is why real-time two-way sync removes a booked slot the moment it is taken (Cal.com). Observation is not exclusion.

Who wins when a human and an agent disagree?

Under the ladder, an explicit human approval or override outranks every agent rule. The exception is a hard policy constraint such as a compliance block, which a human cannot override silently; that case escalates to the constraint's owner and is logged.

How do I pick the approval threshold for money-moving actions?

Use your own reversal data. Take the distribution of amounts and the reversal rate per action class, then set the threshold where expected error cost exceeds the cost of an approval minute. Review it each quarter against the decision log.

Do per-field merge rules make the precedence ladder unnecessary?

No, they reduce how often it runs. Different-field edits never conflict, so the ladder handles only same-field writes and resource claims. It still decides those, and it still decides resource conflicts such as two agents reserving the same budget.

What belongs in a decision log entry?

Record the policy version, both action ids, the winning action, the rule that decided, any human approver, and the outcome including any reversal. The log is append-only and should be reviewed on a schedule to find missing rules and justify threshold changes.

Sources

Sources

  1. Conflict Resolution Playbook: How Agentic AI Systems De ...
  2. Resolving Conflicting Constraints in Multi-Agent ...
  3. Check if date ranges overlap
  4. How to Prevent Double Booking Across Multiple Google ...
  5. Double Booking: What It Is and How to Stop It for Good ...
  6. Agentic Payments: How AI Agents Move Money
  7. Idempotent requests | Stripe API Reference
  8. What is an API? - Application Programming Interfaces ...
  9. AI Receptionist Human Handoff, Controls & Review Mode | Elva
  10. AI Receptionist Limitations and Safe Handoff | VocalOps
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles