Configuring Policy Conflict Resolution with ConflictResolutionStrategy in the Agent Governance Toolkit

The ConflictResolutionStrategy enum defines how the Microsoft Agent Governance Toolkit selects a winning decision when multiple policy rules generate conflicting candidate outcomes, supporting four strategies: DENY_OVERRIDES, ALLOW_OVERRIDES, PRIORITY_FIRST_MATCH (default), and MOST_SPECIFIC_WINS.

Policy conflict resolution in the microsoft/agent-governance-toolkit ensures deterministic access control when overlapping governance rules apply to agent requests. When the policy engine evaluates a request, it collects candidate decisions from every matching rule and uses a configurable ConflictResolutionStrategy to determine the final outcome. The resolution process is handled by the PolicyConflictResolver class, which ranks candidates based on action type, priority values, or policy scope specificity.

Understanding Conflict Resolution Strategies

The toolkit provides four distinct strategies in the ConflictResolutionStrategy enum defined in agent_os/policies/conflict_resolution.py (lines 57-64). Each strategy implements a different decision hierarchy for resolving conflicts between candidate decisions.

Available Resolution Strategies

DENY_OVERRIDES adopts a restrictive security posture where any deny rule takes precedence. If multiple candidates exist and at least one specifies a deny action, that decision wins regardless of priority or scope. Only when no deny rules are present does the highest-priority allow rule prevail.

ALLOW_OVERRIDES implements the opposite approach, favoring permissive access. Any allow rule automatically wins over deny rules. If no allow rules exist in the candidate set, the resolver falls back to selecting the highest-priority deny decision.

PRIORITY_FIRST_MATCH (the default) sorts candidates by their assigned priority value in descending order. The candidate with the highest integer priority wins the conflict, regardless of whether the action is allow or deny. This preserves legacy v1.0 toolkit behavior.

MOST_SPECIFIC_WINS evaluates the PolicyScope associated with each candidate, ranking by specificity where AGENT > ORGANIZATION > TENANT > GLOBAL (as defined in lines 66-76). When candidates share the same scope level, the strategy breaks ties using the priority value.

Core Data Models

The resolution process relies on several Pydantic models defined in the canonical implementation. The CandidateDecision class (lines 87-109) encapsulates a rule's action, priority, scope, and audit metadata including the policy name, rule name, and approver information.

The PolicyConflictResolver class (lines 42-53) serves as the execution engine. It accepts a ConflictResolutionStrategy during initialization and exposes a resolve() method that processes a list of CandidateDecision objects and returns a ResolutionResult.

The ResolutionResult object (lines 31-40) contains the winning decision, the strategy applied, the count of candidates examined, a boolean indicating whether a genuine conflict occurred, and a human-readable trace log explaining the selection rationale.

Configuring the Policy Engine

Configure the conflict resolution strategy when initializing the policy engine. The Policy class constructor in agentmesh/governance/policy.py (lines 491-513) accepts a conflict_strategy string parameter and internally converts it to the corresponding enum value.

from agentmesh.governance.policy import Policy

# Initialize with MOST_SPECIFIC_WINS strategy

engine = Policy(
    conflict_strategy="most_specific_wins"
)

# Load and evaluate policies as usual

engine.load_policy(my_policy_definition)
result = engine.evaluate(request_context)

Valid string identifiers include "deny_overrides", "allow_overrides", "priority_first_match", and "most_specific_wins". Once configured, the engine automatically applies the selected strategy during every evaluation cycle without requiring manual intervention.

Resolving Conflicts Programmatically

For advanced scenarios requiring direct control, instantiate PolicyConflictResolver explicitly with your preferred strategy and pass a list of CandidateDecision objects.

from agentmesh.governance.conflict_resolution import (
    ConflictResolutionStrategy,
    CandidateDecision,
    PolicyConflictResolver,
    PolicyScope,
)

# Build candidate decisions from matching rules

candidates = [
    CandidateDecision(
        action="allow",
        priority=10,
        scope=PolicyScope.GLOBAL,
        policy_name="global-policy",
        rule_name="allow-everything",
    ),
    CandidateDecision(
        action="deny",
        priority=5,
        scope=PolicyScope.AGENT,
        policy_name="agent-override",
        rule_name="no-external-calls",
    ),
]

# Apply DENY_OVERRIDES strategy

resolver = PolicyConflictResolver(ConflictResolutionStrategy.DENY_OVERRIDES)
result = resolver.resolve(candidates)

print(f"Winner: {result.winning_decision.rule_name} -> {result.winning_decision.action}")
print("\n".join(result.resolution_trace))

This pattern is useful for unit testing custom rules or implementing custom policy evaluation pipelines outside the standard engine flow.

Implementation Architecture and Backwards Compatibility

The codebase maintains backwards compatibility through a shim layer located at agentmesh/governance/conflict_resolution.py (lines 19-34). This module attempts to re-export the canonical implementation from agent_os/policies/conflict_resolution.py when the optional agent_os package is available, otherwise falling back to a pure-Python implementation in _conflict_resolution_impl.py (lines 22-70).

This architecture ensures consistent import paths regardless of deployment context:


# Works with or without agent_os installed

from agentmesh.governance.conflict_resolution import PolicyConflictResolver

The canonical implementation in agent_os/policies/conflict_resolution.py serves as the source of truth for ConflictResolutionStrategy, PolicyScope, CandidateDecision, and PolicyConflictResolver definitions.

Summary

  • ConflictResolutionStrategy provides four resolution modes: DENY_OVERRIDES, ALLOW_OVERRIDES, PRIORITY_FIRST_MATCH (default), and MOST_SPECIFIC_WINS.
  • Configure the strategy in Policy.__init__ using the conflict_strategy parameter with lowercase string identifiers.
  • The PolicyConflictResolver class executes the resolution logic on lists of CandidateDecision objects, producing a ResolutionResult with audit traces.
  • PolicyScope specificity (AGENT > ORGANIZATION > TENANT > GLOBAL) determines rankings when using MOST_SPECIFIC_WINS.
  • The agentmesh.governance.conflict_resolution module provides a stable import interface that automatically selects the appropriate underlying implementation.

Frequently Asked Questions

How do I change the default conflict resolution strategy for all policy evaluations?

Pass the desired strategy identifier to the Policy constructor via the conflict_strategy parameter. According to the source code in agentmesh/governance/policy.py (lines 491-513), the constructor converts this string to a ConflictResolutionStrategy enum and initializes the internal PolicyConflictResolver. For example, use conflict_strategy="deny_overrides" to ensure deny rules always take precedence.

What happens when two rules have identical priority and scope under PRIORITY_FIRST_MATCH?

The resolver maintains the original candidate order during the priority sort (descending). When priority values are equal, the first candidate encountered in the input list wins the tie. The resolution_trace in the ResolutionResult documents which candidate was selected and why, enabling audit verification of tie-breaking behavior.

Can I use different conflict resolution strategies for different policy sets?

Each Policy engine instance maintains a single conflict resolution strategy configured at initialization. To use different strategies for different policy sets, instantiate separate Policy objects with distinct conflict_strategy values. Alternatively, invoke PolicyConflictResolver directly with different strategies for ad-hoc evaluations without relying on the engine's default configuration.

How does MOST_SPECIFIC_WINS determine scope specificity?

The strategy ranks candidates by the PolicyScope enum value defined in conflict_resolution.py (lines 66-76). The specificity hierarchy is AGENT (most specific) > ORGANIZATION > TENANT > GLOBAL (least specific). When candidates share the same scope level, the resolver breaks ties using the numeric priority value assigned to each rule.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →