DEV Community

Cover image for Agent-Ready Commerce, Part 4: Making Policies Machine-Readable
Dimitrios S. Sfyris
Dimitrios S. Sfyris

Posted on • Edited on

Agent-Ready Commerce, Part 4: Making Policies Machine-Readable

The difficult policy question in agent-ready commerce is not whether the platform has a return policy page.

The difficult question is whether the platform can safely answer this:

Can an agent tell this buyer, in this region, for this product, through this channel, that this item can be returned under these conditions?

That is a different problem.

A public policy page may exist. A product page may link to it. A support team may understand the exceptions. A human buyer may be able to read the page and make a reasonable interpretation. None of that means an AI agent should treat the page as an authoritative decision source.

For agent-facing systems, policy has to move from text that humans interpret into structured commercial facts that systems can evaluate. Storing the words in a database is only the first step. The platform must also model where the policy applies, what evidence supports it, whether it is current, whether another rule takes precedence, and whether an agent may quote it.

A policy is not machine-readable just because it has been converted into JSON. A policy becomes machine-usable when the platform can answer:

What claim is being made?
Where does it apply?
Which source supports it?
Is the source current?
Does another source disagree?
Is the claim safe for an agent to quote?
Which actions does the claim support?
Enter fullscreen mode Exit fullscreen mode

Series context

This is the fourth article in the Agent-Ready Commerce series.

Part 1 introduced the broader architecture model:

Facts → Eligibility → Authority → State transition → Evidence → Audit
Enter fullscreen mode Exit fullscreen mode

Part 2 focused on commercial truth. It argued that catalog data is not enough. A platform needs source-backed, freshness-aware facts before agents or other systems can safely rely on product information.

Part 3 focused on action eligibility. It argued that “available” is too broad. A product may be discoverable but not checkout-ready, comparable but not policy-quotable, or checkout-ready for a human flow but not eligible for delegated payment.

This article focuses on policy structure.

The central argument is that agent-ready commerce platforms should not ask agents to interpret free-text policy pages as if they were executable rules. Returns, shipping, warranty, cancellation, regional restrictions, and business-buyer rules need to be modeled as policy facts with explicit scope and evidence. Those facts then feed eligibility decisions.

Policy pages are communication, not decision boundaries

A policy page is usually written to communicate terms to a human reader. It often combines general rules, exceptions, legal language, support instructions, category-specific notes, regional differences, and operational constraints in one document.

That is useful for a person. It is not a stable decision boundary for an agent.

Consider a return policy page that says:

Most products can be returned within 30 days of delivery, provided they are unused and returned in their original packaging. Some categories, clearance items, customized products, business orders, and international shipments may be subject to different terms.
Enter fullscreen mode Exit fullscreen mode

A human can read this and understand that details may vary. An agent cannot safely turn that paragraph into a precise product-level claim without additional structure.

The paragraph does not answer:

Does this apply to Travel Bags?
Does it apply to SKU BAG-TRAVEL-42?
Does it apply to EU buyers?
Does it apply to US buyers?
Does it apply to business buyers?
Does it apply to marketplace orders?
Does a clearance campaign override it?
Is there a newer source?
Is the exception list complete?
Can the agent quote the 30-day window, or only link to the policy page?
Enter fullscreen mode Exit fullscreen mode

If the platform does not answer those questions, the agent has to infer them. That moves policy interpretation into the wrong layer.

The platform owns commercial authority. The agent should not become the policy engine.

The useful unit is a policy claim

A policy claim is one specific statement with a defined scope, source, lifecycle, and allowed use. A better starting point is therefore to treat a policy as a set of claims.

A policy claim is a statement the platform may rely on under specific conditions.

For example:

Travel Bags sold to EU consumer buyers through the storefront or agent channel may be returned within 30 days if unused and in original packaging.
Enter fullscreen mode Exit fullscreen mode

That is more useful than:

Return policy: 30 days
Enter fullscreen mode Exit fullscreen mode

The second version looks structured, but it is not sufficiently scoped. It omits category, region, buyer type, channel, conditions, and source.

A policy claim needs at least six dimensions:

Domain:        returns, shipping, warranty, cancellation, restriction
Applicability: product, category, region, buyer type, channel
Value:         the actual rule or term
Evidence:      source documents, source records, review records, hashes
Lifecycle:     active, expired, superseded, draft, revoked
Quotability:  whether an agent may use the claim in generated language
Enter fullscreen mode Exit fullscreen mode

For some systems, precedence should be added as a seventh dimension because overlapping policies are common.

This claim-based model is the main difference between a policy page and machine-readable policy.

A page says something.

A policy claim states one thing and keeps the conditions attached. Those conditions include scope, evidence, lifecycle, freshness, allowed use, and the surfaces on which the statement may appear.

Projection axes are the separate reasons a claim may or may not be usable in a specific output. The useful idea is simple: stale, out-of-scope, unsupported, and surface-refused claims should not collapse into one vague safe or unsafe flag.

The Travel Backpack example

Continue with the running example from Part 2 and Part 3:

Product: Travel Backpack
SKU: BAG-TRAVEL-42
Price: €129
Catalog status: active
Inventory status: in_stock
Category: Travel Bags
Enter fullscreen mode Exit fullscreen mode

The commercial truth layer currently says:

Price: fresh
Inventory: stale
Return policy: missing for Travel Bags
Warranty policy: known
Shipping policy: known for EU, unknown for US
Generated description: pending review
Feed publication: last published yesterday
Enter fullscreen mode Exit fullscreen mode

This is a useful example because the product is not obviously broken. A normal storefront can still render it. The product has a name, SKU, price, category, and stock status. A human can view the page.

The problem appears when the platform has to support agent actions.

An agent may ask:

Can I show this product to the buyer?
Can I compare it with similar backpacks?
Can I tell the buyer the return terms?
Can I quote EU shipping?
Can I quote US shipping?
Can I prepare checkout?
Can I proceed toward delegated payment?
Enter fullscreen mode Exit fullscreen mode

The answers are not the same.

The product can be discovered. It can probably be compared on known product facts. EU shipping may be quotable if the EU shipping fact is active and source-backed. Warranty may be quotable if the warranty fact is known and approved.

But return-policy quotation should be blocked because the return policy is missing for the Travel Bags category. US shipping quotation should also be blocked because US shipping policy is unknown.

Checkout may be blocked if complete return and shipping policy coverage is required before checkout preparation. Delegated payment is blocked because checkout preparation is blocked and payment authority is a separate concern.

This is why policy structure matters. The product is not simply “available” or “unavailable.” Different policy facts support different actions.

Policy text and policy facts are different artifacts

A commerce platform may still need public policy pages. Buyers need readable explanations. Support teams need links. Legal and operations teams may require reviewed wording. Policy text is not going away.

The design issue is whether the same text is also treated as the system’s operational policy model.

In an agent-ready platform, it is safer to separate the artifacts:

Policy text:
Human-readable explanation of terms.

Policy fact:
Structured claim used by systems to evaluate actions.

Generated policy summary:
Derived language produced from policy facts or approved sources.
Enter fullscreen mode Exit fullscreen mode

These artifacts can be linked, but they should not be confused.

A return policy page might include this sentence:

Eligible Travel Bags may be returned within 30 days if unused and returned in original packaging.
Enter fullscreen mode Exit fullscreen mode

The corresponding policy fact could be represented like this:

type PolicyDomain =
  | "returns"
  | "shipping"
  | "warranty"
  | "cancellation"
  | "regional_restriction"
  | "business_buyer_rule";

type BuyerType = "consumer" | "business";
type Channel = "storefront" | "agent" | "marketplace" | "support";

type PolicyApplicability = {
  productIds?: string[];
  skuIds?: string[];
  categoryIds?: string[];
  regions?: string[];
  buyerTypes?: BuyerType[];
  channels?: Channel[];
};

type SourceRef = {
  sourceId: string;
  sourceType:
    | "policy_page"
    | "legal_document"
    | "admin_entry"
    | "commerce_backend"
    | "supplier_feed"
    | "operator_review";
  capturedAt: string;
  contentHash?: string;
  reviewedBy?: string;
};

type PolicyLifecycle = {
  status: "draft" | "active" | "superseded" | "expired" | "revoked";
  effectiveFrom: string;
  effectiveTo?: string;
  reviewedAt?: string;
  nextReviewDueAt?: string;
};

type Quotability = {
  status: "quotable" | "not_quotable" | "limited";
  allowedUses?: Array<"exact_value" | "summary" | "source_link_only">;
  reasons: string[];
};

type PolicyFact = {
  id: string;
  domain: PolicyDomain;
  appliesTo: PolicyApplicability;
  value: PolicyValue;
  sourceRefs: SourceRef[];
  lifecycle: PolicyLifecycle;
  quotability: Quotability;
};
Enter fullscreen mode Exit fullscreen mode

The important part is not the exact TypeScript shape. The important part is that the fact contains the dimensions required for decision-making.

The fact does not merely say “30 days.” It says where that claim applies, what source supports it, whether the fact is active, and whether an agent may quote it.

Policy values should be typed by domain

A generic value: string field is usually not enough.

Different policy domains need different structures. A return policy is not shaped like a shipping policy. A warranty policy is not shaped like a regional restriction. A cancellation rule is not shaped like a business-buyer rule.

A simplified policy value model might look like this:

type PolicyValue =
  | ReturnPolicyValue
  | ShippingPolicyValue
  | WarrantyPolicyValue
  | CancellationPolicyValue
  | RegionalRestrictionValue
  | BusinessBuyerRuleValue;

type ReturnPolicyValue = {
  kind: "return_policy";
  returnWindowDays: number;
  conditions: Array<"unused" | "original_packaging" | "defective_only">;
  exclusions?: string[];
};

type ShippingPolicyValue = {
  kind: "shipping_policy";
  supportedRegions: string[];
  methods: Array<{
    code: string;
    label: string;
    estimatedDays?: {
      min: number;
      max: number;
    };
  }>;
  restrictions?: string[];
};

type WarrantyPolicyValue = {
  kind: "warranty_policy";
  durationMonths: number;
  coverage: string[];
  exclusions?: string[];
};

type CancellationPolicyValue = {
  kind: "cancellation_policy";
  allowedBeforeStatuses: Array<"paid" | "packed" | "shipped" | "fulfilled">;
  cutoffDescription?: string;
};

type RegionalRestrictionValue = {
  kind: "regional_restriction";
  restriction:
    | "not_sellable"
    | "not_shippable"
    | "requires_manual_review"
    | "source_link_only";
  reason: string;
};

type BusinessBuyerRuleValue = {
  kind: "business_buyer_rule";
  rule:
    | "consumer_terms_apply"
    | "business_terms_override"
    | "final_sale"
    | "manual_contract_required";
  notes?: string;
};
Enter fullscreen mode Exit fullscreen mode

This structure prevents a common failure mode: reducing every policy into a short natural-language summary and then asking the agent to interpret it again.

If a return window matters, model the return window. If cancellation depends on order state, model the allowed states. If shipping depends on region, model the supported regions. If business buyers have different rules, represent that difference directly.

The goal is not to eliminate text. The goal is to keep system decisions from depending on unstructured text interpretation at runtime.

Applicability is where many policy models fail

The hardest part of policy modeling is often not the value. It is the scope.

A platform may know that a 30-day return policy exists. That still does not mean it applies to the Travel Backpack.

A policy can be scoped by:

Product
SKU
Category
Brand
Region
Buyer type
Sales channel
Marketplace
Campaign
Order value
Fulfillment method
Supplier
Effective date
Order state
Enter fullscreen mode Exit fullscreen mode

The correct set depends on the business. A simple platform may only need category, region, buyer type, and channel. A marketplace or international commerce system may need more.

The risk is not that the platform lacks policy text. The risk is that the platform applies a true policy to the wrong context.

For the Travel Backpack, a useful return-policy fact would need to answer:

Does this return rule apply to category Travel Bags?
Does it apply to SKU BAG-TRAVEL-42?
Does it apply to EU buyers?
Does it apply to US buyers?
Does it apply to consumer buyers?
Does it apply to business buyers?
Does it apply when the product is sold through an agent channel?
Enter fullscreen mode Exit fullscreen mode

If the platform cannot answer those questions, the fact may exist but not be usable.

That is why “policy exists” and “policy coverage exists for this action” should be treated as different states.

Coverage is not the same as permission

Coverage asks whether the platform has an applicable policy fact. Permission asks whether that fact may be used for the requested action. A missing policy fact should not automatically mean the policy outcome is negative.

If the return policy for Travel Bags is missing, that does not necessarily mean Travel Bags cannot be returned. It means the platform does not currently have a source-backed policy fact that supports a return-policy claim for that context.

This distinction matters because agent-facing systems should avoid converting unknown into false.

For the Travel Backpack:

Return policy missing for Travel Bags
Enter fullscreen mode Exit fullscreen mode

does not mean:

This product is not returnable.
Enter fullscreen mode Exit fullscreen mode

It means:

The platform cannot currently quote return terms for this product/category context.
Enter fullscreen mode Exit fullscreen mode

Similarly:

US shipping policy unknown
Enter fullscreen mode Exit fullscreen mode

does not necessarily mean:

This product cannot ship to the US.
Enter fullscreen mode Exit fullscreen mode

It means:

The platform cannot currently quote US shipping terms or prepare US checkout without additional validation.
Enter fullscreen mode Exit fullscreen mode

A useful policy coverage model might distinguish these states:

type PolicyCoverageStatus =
  | "known"
  | "missing"
  | "stale"
  | "conflicting"
  | "not_applicable"
  | "requires_review";

type PolicyCoverage = {
  productId: string;
  domain: PolicyDomain;
  context: {
    region: string;
    buyerType: BuyerType;
    channel: Channel;
  };
  status: PolicyCoverageStatus;
  selectedFactIds: string[];
  blockers: string[];
};
Enter fullscreen mode Exit fullscreen mode

This allows eligibility decisions to be precise.

Known policy coverage may allow quotation or checkout. Missing coverage may block quotation. Conflicting coverage may create an operator task. Not applicable may be valid if the platform has explicit evidence that a domain does not apply.

Unknown is not enough. The reason for unknown matters.

Evidence should be attached to the claim, not reconstructed later

Policy facts need evidence because agent-facing claims must be traceable.

If an agent says:

This product has a 24-month warranty.
Enter fullscreen mode Exit fullscreen mode

the platform should be able to explain which source supported the statement.

Evidence can come from different sources:

Public policy page
Legal document
Admin entry
Supplier feed
Commerce backend
Contract record
Operator review
Generated summary approval
Enter fullscreen mode Exit fullscreen mode

The evidence reference should not be an afterthought. It should be part of the policy fact.

For example:

const warrantyFact: PolicyFact = {
  id: "policyfact_warranty_bag_travel_42_eu_consumer",
  domain: "warranty",
  appliesTo: {
    skuIds: ["BAG-TRAVEL-42"],
    regions: ["EU"],
    buyerTypes: ["consumer"],
    channels: ["storefront", "agent"]
  },
  value: {
    kind: "warranty_policy",
    durationMonths: 24,
    coverage: ["manufacturing_defects"],
    exclusions: ["normal_wear", "accidental_damage"]
  },
  sourceRefs: [
    {
      sourceId: "supplier_warranty_terms_2026_05",
      sourceType: "supplier_feed",
      capturedAt: "2026-06-10T08:30:00Z",
      contentHash: "sha256:..."
    },
    {
      sourceId: "ops_review_8841",
      sourceType: "operator_review",
      capturedAt: "2026-06-11T12:15:00Z",
      reviewedBy: "ops"
    }
  ],
  lifecycle: {
    status: "active",
    effectiveFrom: "2026-06-01T00:00:00Z",
    reviewedAt: "2026-06-11T12:15:00Z",
    nextReviewDueAt: "2026-09-01T00:00:00Z"
  },
  quotability: {
    status: "quotable",
    allowedUses: ["exact_value", "summary"],
    reasons: []
  }
};
Enter fullscreen mode Exit fullscreen mode

This gives the platform a stable chain:

Claim → Source → Review → Quotability → Eligibility → Audit
Enter fullscreen mode Exit fullscreen mode

That chain is more useful than storing policy text and hoping the agent interprets it correctly.

Freshness and lifecycle should be explicit

Policies change for reasons that are not always visible at the product level.

A shipping region can become unsupported. A supplier can update warranty terms. A return window can change during a campaign. A cancellation policy can change when fulfillment operations change. Business-buyer terms can be updated after contract review. A regional restriction can be added after a compliance decision.

A policy fact should therefore have a lifecycle, not only an updatedAt timestamp.

A timestamp says when a record changed. A lifecycle says whether the fact is valid for commercial use.

Useful lifecycle states include:

draft
active
superseded
expired
revoked
Enter fullscreen mode Exit fullscreen mode

These states are not cosmetic. They affect agent actions.

A draft policy fact should not support quotation. An expired policy fact should not support checkout. A superseded policy fact may remain important for historical orders but should not be selected for new claims. A revoked policy fact may need to invalidate generated summaries and feed entries.

When policy authority is invalidated, the platform should retain the previous authority descriptor and hash for audit and bounded reassessment. Repairing the exact parent fact can make dependent claims or facts ready for review, but it should not restore quotation, checkout, or delegated-payment authority without a fresh owner decision.

For the Travel Backpack, suppose EU shipping was known yesterday but the carrier terms changed today. If the EU shipping fact is now stale or revoked, the platform should not keep quoting the old delivery terms because a feed entry still contains them.

This is why policy freshness belongs in commercial truth, not only in CMS publishing metadata.

Conflicts are domain events, not edge cases

Policy conflicts are common enough that the model should treat them as first-class.

Examples:

A public return page says Travel Bags can be returned within 30 days.
A category admin rule says Travel Bags are returnable only if unused.
A campaign rule says clearance items are final sale.
A product is currently in a clearance campaign.
Enter fullscreen mode Exit fullscreen mode

This may be resolvable if precedence is explicit. The campaign rule may override the category rule. The category condition may refine the public page.

But if precedence is not explicit, the platform has a conflict. It should not allow an agent to pick one interpretation.

A conflict model can look like this:

type PolicyConflict = {
  id: string;
  domain: PolicyDomain;
  appliesTo: PolicyApplicability;
  conflictingFactIds: string[];
  conflictType:
    | "different_value"
    | "scope_overlap"
    | "missing_precedence"
    | "source_outdated"
    | "ambiguous_exception";
  severity: "warning" | "blocker";
  status: "open" | "resolved" | "accepted_risk";
  detectedAt: string;
};
Enter fullscreen mode Exit fullscreen mode

A conflict should affect quotability and eligibility.

If return-policy sources disagree for Travel Bags, the product may still be discoverable. It may still be comparable on non-policy facts. But return-policy quotation should be blocked until the conflict is resolved or an approved precedence rule selects the winning fact.

The platform should prefer a blocked claim over an unsupported confident claim.

Precedence should be modeled, not remembered

Policy conflicts often arise because several valid policies overlap.

A platform may have:

Global policy
Regional policy
Channel policy
Buyer-type policy
Category policy
Product policy
Campaign policy
Order-specific override
Enter fullscreen mode Exit fullscreen mode

If two policies apply, the system needs to know which one wins.

One possible precedence order is:

Order-specific override
Product-specific policy
Campaign-specific policy
Category policy
Buyer-type policy
Regional policy
Global policy
Enter fullscreen mode Exit fullscreen mode

This order is not universal. The correct precedence model depends on the business, legal requirements, fulfillment model, and sales channels.

The architectural point is that precedence should not live in scattered conditionals or support-team memory. It should be part of the policy model.

When a selected fact wins, the platform should be able to explain why:

Selected policy:
Campaign-specific final-sale rule

Suppressed policy:
Category-level 30-day return rule

Reason:
Campaign-specific policy has higher precedence for products currently marked as clearance items.
Enter fullscreen mode Exit fullscreen mode

When no precedence rule exists, the system should not silently choose. It should mark the claim as conflicting, block quotation, and create an operator task.

This is especially important for agents because natural language can hide uncertainty. A human support agent may know to be careful. An AI agent may produce a clean answer unless the platform gives it a structured blocker.

Quotability is not the same as truth

A policy fact can be true and applicable without being safe to quote. Quotability is the separate decision that allows the platform to expose the wording or an approved summary to a specific audience and use.

That sounds strange at first, but it reflects real commerce constraints.

A policy may be visible to humans as a general page but not precise enough for product-level quotation. A policy may be true for the storefront but not for marketplace orders. A policy may be correct for consumers but not business buyers. A policy may be under legal review. A policy may be generated from source material but not approved. A policy may be valid internally but should only be exposed through a source link.

Quotability controls how a policy fact can be used in agent-facing language.

This is where policy availability becomes claim projection. The platform is no longer asking only whether a policy fact exists. It is asking whether this exact claim may be projected into language for this use, surface, buyer context, and source state.

For example:

const returnPolicyCoverageForTravelBags = {
  productId: "BAG-TRAVEL-42",
  domain: "returns",
  context: {
    categoryId: "travel_bags",
    region: "EU",
    buyerType: "consumer",
    channel: "agent"
  },
  coverage: "missing",
  quotability: {
    status: "not_quotable",
    reasons: ["missing_return_policy"]
  }
};
Enter fullscreen mode Exit fullscreen mode

This does not say that the product has no return rights. It says the platform cannot safely allow an agent to quote return terms for this product and context.

Quotability can also be limited:

const regionalRestrictionFact = {
  domain: "regional_restriction",
  appliesTo: {
    categoryIds: ["travel_bags"],
    regions: ["US"],
    channels: ["agent"]
  },
  value: {
    kind: "regional_restriction",
    restriction: "requires_manual_review",
    reason: "US shipping terms are not approved for agent quotation."
  },
  quotability: {
    status: "limited",
    allowedUses: ["source_link_only"],
    reasons: ["policy_facts_incomplete"]
  }
};
Enter fullscreen mode Exit fullscreen mode

In that case, an agent may be allowed to say:

I cannot quote US shipping terms for this product. Please review the merchant’s shipping policy or contact support.
Enter fullscreen mode Exit fullscreen mode

But it should not generate a specific shipping promise.

Quotability creates a boundary between what the platform knows, what it can show, and what an agent may say. It should not collapse every reason into one boolean. A claim can be fresh but out of scope, in scope but stale, usable for support but refused for agent quotation, or blocked because an upstream derived claim was refused.

Allowed-use matrix

Policy facts should support action-specific use.

A missing return policy should not necessarily remove a product from discovery. A stale shipping policy should not necessarily prevent comparison on product dimensions. A conflicting warranty policy should block warranty quotation but may not affect EU shipping quotation.

A simplified allowed-use matrix could look like this:

Action Policy requirement Missing policy Stale policy Conflicting policy
discover Basic sellability and regional visibility Usually allowed unless the missing policy affects visibility Usually allowed if no policy claim is made Allowed only if conflict does not affect visibility
compare Facts used in comparison must be quotable Allowed if comparison avoids missing policy domain Allowed for non-policy comparison Block policy-based comparison
quote_policy Requested policy domain must be known, active, non-conflicting, and quotable Blocked Blocked or requires review Blocked
prepare_checkout Required checkout policy coverage must be complete for the context Blocked if required policy is missing Blocked or requires revalidation Blocked
delegate_payment Valid checkout state and payment authority must both exist Blocked Blocked Blocked

For the Travel Backpack:

Action Result Reason
discover Allowed Product identity and basic catalog facts are known
compare Allowed with limits Product can be compared on known facts, but not on return terms
quote_policy: returns Blocked Return policy is missing for Travel Bags
quote_policy: warranty Allowed if quotable Warranty policy is known
quote_policy: EU shipping Allowed if quotable EU shipping policy is known
quote_policy: US shipping Blocked US shipping policy is unknown
prepare_checkout Blocked Return coverage is missing; inventory is stale from Part 3
delegate_payment Blocked Checkout state is not valid for payment; payment authority is separate

This is the same principle from Part 3 applied to policy. A product does not have one policy status. It has policy coverage per domain, context, and action.

Policy facts feed eligibility decisions

Policy facts are not an isolated content model. They are inputs to eligibility.

A useful flow is:

Policy sources
      ↓
Policy facts
      ↓
Commercial truth snapshot
      ↓
Eligibility decision
      ↓
Agent response, checkout state, feed projection, operator task
Enter fullscreen mode Exit fullscreen mode

For example, when evaluating whether an agent may quote the return policy for the Travel Backpack, the eligibility layer might ask the policy layer:

Product: BAG-TRAVEL-42
Category: Travel Bags
Action: quote_policy
Policy domain: returns
Region: EU
Buyer type: consumer
Channel: agent
Enter fullscreen mode Exit fullscreen mode

The policy layer may respond:

No active quotable return-policy fact applies to Travel Bags for EU consumer buyers through the agent channel.
Enter fullscreen mode Exit fullscreen mode

The eligibility decision can then be structured:

type AgentCommerceDecisionAction =
  | "discover"
  | "compare"
  | "quote_policy"
  | "add_to_cart"
  | "prepare_checkout"
  | "delegate_payment"
  | "complete_checkout"
  | "show_generated_claim"
  | "explain";

type EligibilityDecision = {
  productId: string;
  requestedAction: AgentCommerceDecisionAction;
  context: {
    policyDomain?: PolicyDomain;
    region?: string;
    buyerType?: BuyerType;
    channel?: Channel;
  };
  result:
    | "allowed"
    | "blocked"
    | "requires_review"
    | "requires_revalidation"
    | "requires_confirmation";
  blockers: Array<{
    code: string;
    message: string;
    nextAction?: string;
  }>;
  evidenceRefs: SourceRef[];
  evaluatedAt: string;
};

const returnQuoteDecision: EligibilityDecision = {
  productId: "BAG-TRAVEL-42",
  requestedAction: "quote_policy",
  context: {
    policyDomain: "returns",
    region: "EU",
    buyerType: "consumer",
    channel: "agent"
  },
  result: "blocked",
  blockers: [
    {
      code: "missing_return_policy",
      message:
        "No active quotable return-policy fact applies to Travel Bags for EU consumer buyers through the agent channel.",
      nextAction:
        "Attach or approve return-policy coverage for the Travel Bags category."
    }
  ],
  evidenceRefs: [
    {
      sourceId: "policy:returns:travel-bags:missing",
      sourceType: "commerce_backend",
      capturedAt: "2026-06-28T09:00:00Z",
      contentHash: "<sha256-of-canonical-missing-coverage-snapshot>"
    }
  ],
  evaluatedAt: "2026-06-28T09:00:00Z"
};
Enter fullscreen mode Exit fullscreen mode

This decision is more useful than a boolean.

The agent can avoid making an unsupported claim. The checkout service can block preparation. The admin UI can create a remediation task. The audit log can show why the product was not policy-quotable.

Operator tasks should describe commercial impact

Policy problems should not remain hidden inside validation errors.

A useful operator task does not merely say:

Missing return policy.
Enter fullscreen mode Exit fullscreen mode

It explains the impact:

Return-policy coverage is missing for Travel Bags.

Affected product:
BAG-TRAVEL-42

Affected actions:
Agents can discover and compare the product, but cannot quote return terms.
Checkout preparation is blocked if complete policy coverage is required.

Suggested action:
Attach or approve a return-policy fact for Travel Bags, including region, buyer type, channel, effective dates, evidence, and quotability.
Enter fullscreen mode Exit fullscreen mode

For US shipping, the task might say:

US shipping policy is unknown for Travel Bags.

Affected actions:
Agents cannot quote US shipping terms.
US checkout preparation is blocked or requires manual review, depending on checkout policy.

Suggested action:
Add US shipping coverage, explicitly mark US as unsupported, or route US orders to manual review.
Enter fullscreen mode Exit fullscreen mode

This is one of the practical benefits of structured policy facts. They connect missing data to specific business capability.

Operators do not only need to know that data is incomplete. They need to know which agent actions are affected and what decision would unblock them.

Generated policy summaries are derived artifacts

Policy summaries are useful, but they should not become authority automatically.

An agent-facing system may want to say:

This product has known EU shipping terms and a known warranty. Return terms are not currently available for this category.
Enter fullscreen mode Exit fullscreen mode

That kind of summary can improve user experience. The danger is treating generated language as the source of truth.

The safer direction is:

Authoritative source
      ↓
Structured policy facts
      ↓
Applicability and quotability decision
      ↓
Generated summary with source fact references
      ↓
Projection gate and projection axes
      ↓
Surface projection
Enter fullscreen mode Exit fullscreen mode

The unsafe direction is:

Policy page
      ↓
Generated summary
      ↓
Agent authority
Enter fullscreen mode Exit fullscreen mode

A generated summary should reference the facts it used and the uses for which it is allowed:

type AxisStatus = "passed" | "failed" | "not_evaluated";

type GeneratedPolicySummaryProjection = {
  id: string;
  productId: string;
  status:
    | "allowed"
    | "requires_review"
    | "refused_here"
    | "inherited_refusal"
    | "stale"
    | "out_of_scope"
    | "absent";
  sourceFactRefs: string[];
  derivedFactRefs: string[];
  allowedUses: Array<"feed" | "tool" | "checkout_explanation" | "support">;
  axes: Record<
    "source" | "freshness" | "scope" | "surface" | "use" | "payload" | "taint",
    AxisStatus
  >;
  inheritedRefusalCount: number;
  reviewStatus: "REVIEW_REQUIRED" | "APPROVED" | "BLOCKED";
  generatedAt: string;
  expiresAt?: string;
};
Enter fullscreen mode Exit fullscreen mode

If the summary requires review, it should not be treated as an authoritative policy claim. If one of the underlying facts changes, the summary should be invalidated or regenerated.

When the platform builds the decision envelope, generated claims should appear as derived status rather than source truth:

generatedClaims.status
generatedClaims.claimIds
generatedClaims.sourceFactRefs
generatedClaims.allowedUses
generatedClaims.axes
generatedClaims.blockerCodes
Enter fullscreen mode Exit fullscreen mode

That keeps the grounding discipline explicit: source data becomes a referenced fact; generated language is derived from approved facts; projection decides whether the claim is usable here, refused here, or not grounded for this use. If a summary depends on another refused projection, that refusal should travel with it internally.

The canonical envelope should also keep generated-claim state action-aware. A generated-claim blocker may explain quote_policy or comparison copy, but it should not falsely become the main reason for a delegated-payment decision unless the requested payment action actually depends on that claim.

Business-buyer rules deserve separate modeling

Business-buyer rules are easy to miss because many commerce systems begin with consumer flows.

But business purchases often have different terms:

Returns may be limited or unavailable.
Warranty may depend on contract terms.
Cancellation may require approval.
Payment may use invoices instead of card authorization.
Shipping terms may depend on account agreements.
VAT or tax handling may affect checkout.
Enter fullscreen mode Exit fullscreen mode

A generic consumer return policy should not automatically apply to business buyers unless that is an explicit rule.

For example:

const businessBuyerReturnRule: PolicyFact = {
  id: "policyfact_business_returns_travel_bags_eu",
  domain: "business_buyer_rule",
  appliesTo: {
    categoryIds: ["travel_bags"],
    regions: ["EU"],
    buyerTypes: ["business"],
    channels: ["storefront", "agent"]
  },
  value: {
    kind: "business_buyer_rule",
    rule: "manual_contract_required",
    notes:
      "Business-buyer return terms are governed by account agreement or manual approval."
  },
  sourceRefs: [
    {
      sourceId: "business_terms_admin_2026_06",
      sourceType: "admin_entry",
      capturedAt: "2026-06-20T14:00:00Z"
    }
  ],
  lifecycle: {
    status: "active",
    effectiveFrom: "2026-06-20T00:00:00Z"
  },
  quotability: {
    status: "limited",
    allowedUses: ["source_link_only"],
    reasons: ["BUSINESS_TERMS_REQUIRE_ACCOUNT_CONTEXT"]
  }
};
Enter fullscreen mode Exit fullscreen mode

For an agent, this means the consumer answer and the business-buyer answer may differ for the same SKU.

That difference belongs in the policy model, not in prompt instructions.

Cancellation is state-dependent policy

Cancellation policies are also different from static return policies because they often depend on order state.

A product may be cancellable before payment, after payment but before packing, or before dispatch. Once shipped, cancellation may become a return process instead.

A cancellation policy fact therefore needs to connect policy to state transition.

const cancellationFact: PolicyFact = {
  id: "policyfact_cancellation_standard_eu_consumer",
  domain: "cancellation",
  appliesTo: {
    regions: ["EU"],
    buyerTypes: ["consumer"],
    channels: ["storefront", "agent"]
  },
  value: {
    kind: "cancellation_policy",
    allowedBeforeStatuses: ["paid", "packed"],
    cutoffDescription:
      "Cancellation is allowed before the order is handed to the carrier."
  },
  sourceRefs: [
    {
      sourceId: "cancellation_policy_page",
      sourceType: "policy_page",
      capturedAt: "2026-06-12T09:00:00Z",
      contentHash: "sha256:..."
    }
  ],
  lifecycle: {
    status: "active",
    effectiveFrom: "2026-06-01T00:00:00Z"
  },
  quotability: {
    status: "quotable",
    allowedUses: ["summary"],
    reasons: []
  }
};
Enter fullscreen mode Exit fullscreen mode

This matters because an agent may ask to cancel an order, but the answer depends on state.

Policy says what is allowed.

Execution checks the current order state.

Authority decides whether the actor may request cancellation.

Audit records the result.

Those boundaries should remain separate.

Regional restrictions should not be hidden inside shipping text

Regional restrictions are often mixed into shipping pages, product descriptions, marketplace settings, or fulfillment rules. That makes them easy to miss.

For agent-facing systems, regional restrictions should be explicit because they affect discovery, quotation, checkout, and payment.

A region may be:

Supported for discovery but not checkout
Supported for shipping but not returns
Supported for consumers but not business buyers
Unsupported because of carrier coverage
Unsupported because of legal restriction
Allowed only with manual review
Enter fullscreen mode Exit fullscreen mode

A structured regional restriction can prevent overexposure.

For example:

const usShippingUnknown: PolicyCoverage = {
  productId: "BAG-TRAVEL-42",
  domain: "shipping",
  context: {
    region: "US",
    buyerType: "consumer",
    channel: "agent"
  },
  status: "missing",
  selectedFactIds: [],
  blockers: ["missing_shipping_policy"]
};
Enter fullscreen mode Exit fullscreen mode

The result is not necessarily “do not show the product to US users.” The result may be:

Do not quote US shipping terms.
Do not prepare US checkout without revalidation or manual review.
Do not allow delegated payment for US checkout.
Enter fullscreen mode Exit fullscreen mode

Again, the correct behavior depends on action eligibility.

Protocol adapters should remain thin

Agent-facing protocols and tool interfaces may require policy information in different shapes. A platform may eventually expose policy decisions through ACP- or UCP-style commerce surfaces, MCP tools, AP2-related payment flows, internal feeds, marketplace APIs, or other adapters.

The adapter should not become the policy interpreter.

A thin adapter asks the domain model:

Can this policy be quoted for this product and context?
Which facts support the answer?
Which blockers exist?
What action result should be exposed?
Enter fullscreen mode Exit fullscreen mode

Then it translates the result into the protocol format.

The adapter should not parse policy pages, resolve conflicts, decide precedence, or determine quotability. If each protocol adapter performs its own policy interpretation, the platform will eventually provide inconsistent answers through different surfaces.

Deep protocol integration belongs in Part 5. For Part 4, the policy principle is enough:

Adapters translate policy decisions.
They do not own policy meaning.
Enter fullscreen mode Exit fullscreen mode

Where this model can go wrong

Structured policy facts are useful, but they introduce their own failure modes.

Over-modeling before the business needs it

A platform does not need a full legal rules engine on day one. If the product range is small, regions are limited, and there are no agent-facing checkout actions, a simpler policy model may be enough.

A practical starting point is:

domain
applicability
value
source
lifecycle
quotability
Enter fullscreen mode Exit fullscreen mode

More complex precedence, conflict resolution, campaign overrides, and contract-specific rules can be added when real requirements justify them.

The goal is not architectural completeness. The goal is to avoid letting agents infer commercial terms from ambiguous text.

Treating structured facts as automatically correct

A structured fact can still be wrong.

The category scope may be too broad. The region may be incorrect. The source may be outdated. The review may be missing. A condition may have been simplified too aggressively.

Structure makes facts easier to evaluate. It does not make them true by itself.

That is why source references, lifecycle, review, and audit remain necessary.

Removing too much nuance

Some policy text contains important nuance. Reducing it to a headline value can be dangerous.

For example:

Returns accepted within 30 days
Enter fullscreen mode Exit fullscreen mode

is not equivalent to:

Returns accepted within 30 days if unused, in original packaging, not customized, not clearance, and not restricted by regional law.
Enter fullscreen mode Exit fullscreen mode

A weak structured model can create false precision. It may appear machine-readable while omitting the conditions that actually matter.

Converting unknown into allowed

This is one of the highest-risk failures.

If US shipping is unknown, the system should not apply EU shipping terms by default. If business-buyer returns are unknown, the system should not silently apply consumer terms. If a category policy is missing, the system should not assume the global policy applies unless that inheritance is explicit and approved.

Defaults are policy decisions. They should be represented as policy facts or precedence rules, not hidden in code paths.

Letting generated summaries drift

Generated summaries become risky when underlying facts change.

If a summary says the Travel Backpack has EU shipping terms and a 24-month warranty, the summary should reference the fact IDs used to generate it. If those facts are superseded, the summary should be invalidated.

Otherwise the platform may keep publishing natural language that no longer matches the policy model.

Making quotability global

A fact may be quotable in one context and not another.

Warranty may be quotable for EU consumers but not business buyers. Shipping may be quotable for EU but not US. A policy may be quotable through support but not through an automated agent channel.

Quotability should be evaluated with applicability and the source reference that made it true. A claim grounded against one policy source should not stay quotable after that policy changes.

Turning the policy service into a god service

The policy layer should answer policy questions. It should not own all eligibility, checkout, authority, payment, and protocol behavior.

A clean boundary is:

Policy service:
which policy facts apply, whether they are fresh, whether they conflict, whether they are quotable

Eligibility service:
which actions are allowed for the product and context

Checkout service:
whether checkout state can advance

Authority service:
whether the actor may request the action

Protocol adapter:
how the decision is represented externally
Enter fullscreen mode Exit fullscreen mode

Policy facts are critical inputs. They are not the entire commerce system.

Practical tests for policy facts

Policy tests should be scenario-led, with field-level assertions used to keep the result precise.

A useful case includes:

Product
Category
Region
Buyer type
Channel
Policy domain
Source state
Expected coverage
Expected quotability
Expected eligibility impact
Expected operator work item
Enter fullscreen mode Exit fullscreen mode

For the Travel Backpack:

Scenario Expected result
EU consumer, Travel Bags, return policy missing Return quotation blocked; checkout blocked if return coverage is required
EU consumer, warranty known and quotable Warranty quotation allowed
EU consumer, EU shipping known and quotable EU shipping quotation allowed
US consumer, US shipping unknown US shipping quotation blocked; checkout blocked or requires review
Business buyer, only consumer return policy exists Business return quotation blocked
Conflicting return sources for Travel Bags Return quotation blocked; conflict work item created
Generated return summary pending review Summary cannot be used as authority
Category policy and campaign policy overlap without precedence Quotation blocked; precedence work item created
Expired shipping policy remains linked from a page Shipping quotation blocked until refreshed
Revoked warranty source remains in generated summary Summary invalidated
Exact parent policy is repaired after a dependent claim was invalidated Dependent becomes ready for review; authority is not restored automatically

A test expectation can be expressed like this:

type PolicyScenarioExpectation = {
  productId: string;
  context: {
    region: string;
    buyerType: BuyerType;
    channel: Channel;
  };
  domain: PolicyDomain;
  expectedCoverage: PolicyCoverageStatus;
  expectedQuotability: "quotable" | "not_quotable" | "limited";
  expectedEligibilityBlockers: string[];
  expectedOperatorWorkItems: string[];
};
Enter fullscreen mode Exit fullscreen mode

The value is in testing the relationship between facts, context, action, and outcome.

A policy fact may look correct in isolation but fail when category inheritance, buyer type, region, channel, lifecycle, and quotability are evaluated together.

Policy-change tests are also important, but they do not need to expose internal version labels.

For example:

Given:
An EU shipping policy is active and quotable.

When:
The approved EU shipping terms are updated with different delivery estimates.

Then:
The previous shipping facts are superseded.
New shipping facts become the current approved facts.
Generated summaries based on the previous shipping terms are invalidated.
Agent feed projections are refreshed.
Eligibility decisions can explain which current policy source was used.
Enter fullscreen mode Exit fullscreen mode

This is the level of behavior worth testing when policy facts support agent-facing claims. Rendering the policy page is not enough.

A practical implementation path

A platform can adopt this model incrementally.

The first version does not need to solve every policy problem. It can start with the claims that affect agent-facing actions.

A practical path is:

  1. Define the policy domains that matter.
    Start with returns, shipping, warranty, cancellation, regional restrictions, and business-buyer rules.

  2. Model applicability.
    At minimum, capture product or category, region, buyer type, and channel.

  3. Attach evidence.
    Every policy fact should reference a source, capture time, and ideally a source hash or review record.

  4. Add lifecycle.
    Distinguish active, draft, superseded, expired, and revoked facts.

  5. Add quotability.
    Do not allow agents to quote every visible policy by default.

  6. Feed policy coverage into eligibility.
    Use policy facts to decide quote_policy, prepare_checkout, and delegated-action eligibility.

  7. Create operator tasks from gaps.
    Missing, stale, conflicting, or non-quotable facts should produce remediation work with clear commercial impact.

  8. Treat generated summaries as derived.
    A generated summary should reference facts and source records. It should not become authority automatically.

This path keeps the model grounded. It avoids building a large rules engine before there is a reason, but it also avoids the unsafe default of treating policy pages as executable commercial truth.

The tradeoff

Structured policy modeling adds work.

It requires domain modeling, source references, lifecycle states, conflict detection, quotability rules, eligibility integration, operator workflows, and scenario tests.

For a simple storefront with limited regions and no agent-facing actions, a public policy page and manual support process may be sufficient.

Agent-ready commerce changes the threshold.

Once agents can compare products, quote terms, prepare checkout, or operate under delegated authority, policy ambiguity becomes a systems problem. A free-text page is no longer enough because the platform must decide which claims can be used, in which context, and for which action.

The tradeoff is between publishing convenience and operational reliability.

Free-text policy pages are easier to create.

Structured policy facts are easier to evaluate, test, audit, and connect to eligibility decisions.

The purpose of this model is not to replace human-readable policy. It is to prevent human-readable policy from being treated as a machine decision boundary without the structure required to support that role.

What this changes

Machine-readable policy is not just policy text stored in a structured format.

A policy becomes machine-usable when the platform can evaluate a specific claim in a specific context.

For the Travel Backpack, the platform should be able to say:

The warranty policy is known and quotable.
EU shipping is known and quotable.
US shipping is unknown and not quotable.
Return policy coverage is missing for Travel Bags.
Checkout is blocked if complete policy coverage is required.
Delegated payment is blocked because checkout preparation is blocked.
Enter fullscreen mode Exit fullscreen mode

Those answers cannot be derived safely from a generic policy page at runtime. They require structured policy facts, applicability, evidence, lifecycle, conflict handling, quotability, and eligibility integration.

The useful distinction is:

Policy text communicates terms to humans.
Policy facts support system decisions.
Quotability controls what agents may say.
Eligibility controls what agents may do.
Evidence explains why the platform trusted the claim.
Enter fullscreen mode Exit fullscreen mode

This keeps policy interpretation inside the commerce platform, where it can be reviewed, evaluated, and traced back to sources. It also keeps protocol adapters and AI-generated summaries from becoming accidental sources of commercial authority.

Next in the series

Part 5 will move from domain decisions to integration boundaries:

Agent-Ready Commerce, Part 5: Keeping ACP, UCP, MCP, and AP2 Adapters Thin

That article will examine how agent-facing protocol adapters should translate domain decisions without owning product truth, policy interpretation, eligibility, authority, checkout state, or payment semantics.


About the author

Written by Dimitrios S. Sfyris, Founder & Software Architect at AspectSoft.

AspectSoft designs and develops custom software platforms, e-commerce systems, SaaS infrastructure, integrations, analytics tools, and practical digital products.

You can also follow the AspectSoft LinkedIn page for updates on software platforms, commerce systems, AI tooling, and developer-focused products.

Top comments (0)