Skip to main content

Contradictory Annotation Detection

Contradictory annotations occur when two or more AXAG attributes on the same element express incompatible semantics. These contradictions create ambiguity for agents, which cannot determine the correct interpretation.

Why It Matters

When an agent encounters contradictory annotations, it must either:

  • Guess which attribute to trust (dangerous)
  • Reject the operation entirely (safe but limits functionality)
  • Ask for human clarification (possible but defeats automation)

None of these outcomes are acceptable in production. Contradictions MUST be detected and resolved before deployment.

Common Contradictions

1. Risk Level vs Action Type

A read operation annotated with high risk:

❌ Contradictory — read with high risk
<!-- ❌ Contradictory: reads are inherently safe -->
<button
axag-intent="product.search"
axag-entity="product"
axag-action-type="read"
axag-risk-level="high"
>Search</button>

Rule: AXAG-LINT-010 — Read operations SHOULD NOT have risk level above low.

Fix:

✅ Fix — risk level matches action type
<button
axag-intent="product.search"
axag-entity="product"
axag-action-type="read"
axag-risk-level="none"
>Search</button>

2. Idempotent vs Side Effects

An operation declared idempotent but with non-idempotent side effects:

❌ Contradictory — idempotent with non-idempotent side effects
<!-- ❌ Contradictory: email_sent is not idempotent -->
<button
axag-intent="order.place"
axag-entity="order"
axag-action-type="write"
axag-idempotent="true"
axag-side-effects='["email_sent","inventory_deducted"]'
axag-risk-level="high"
>Place Order</button>

Rule: AXAG-LINT-011 — Idempotent operations MUST NOT declare non-idempotent side effects.

Fix: Either mark as non-idempotent or ensure side effects are truly idempotent (e.g., "email_sent" becomes "email_queued_idempotent").

3. Confirmation Not Required on Destructive Actions

❌ Contradictory — delete without confirmation
<!-- ❌ Contradictory: delete without confirmation -->
<button
axag-intent="user.delete"
axag-entity="user"
axag-action-type="delete"
axag-risk-level="critical"
axag-confirmation-required="false"
>Delete User</button>

Rule: AXAG-LINT-012 — Delete operations with risk level high or critical MUST require confirmation.

4. Approval Without Roles

<!-- ❌ Contradictory: approval required but no roles specified -->
<button
axag-intent="expense.approve"
axag-entity="expense"
axag-action-type="write"
axag-approval-required="true"
axag-risk-level="high"
>Approve</button>

Rule: AXAG-LINT-013 — When axag-approval-required="true", axag-approval-roles MUST be specified.

5. Preconditions Contradicting Action Type

<!-- ❌ Contradictory: create with "entity must exist" precondition -->
<button
axag-intent="product.create"
axag-entity="product"
axag-action-type="write"
axag-preconditions='["product must exist"]'
>Create Product</button>

Rule: AXAG-LINT-014 — Create operations SHOULD NOT require the target entity to already exist.

Detection Rules Summary

RuleContradictionSeverity
AXAG-LINT-010Read + high/critical riskWarning
AXAG-LINT-011Idempotent + non-idempotent side effectsError
AXAG-LINT-012Destructive + no confirmation (high/critical)Error
AXAG-LINT-013Approval required + no approval rolesError
AXAG-LINT-014Create + "must exist" preconditionWarning
AXAG-LINT-015Navigate + side effects declaredWarning
AXAG-LINT-016Non-tenant scope + tenant-only rolesError

CI Integration

# In your CI pipeline
- name: Check for contradictory annotations
run: npx axag-lint --rules contradictions --format=github

Next Steps