Skip to content

feat: add a post-transaction dispute resolution sample - #352

Open
maximusrufus wants to merge 1 commit into
google-agentic-commerce:mainfrom
maximusrufus:samples/dispute-scenario
Open

feat: add a post-transaction dispute resolution sample#352
maximusrufus wants to merge 1 commit into
google-agentic-commerce:mainfrom
maximusrufus:samples/dispute-scenario

Conversation

@maximusrufus

@maximusrufus maximusrufus commented Sep 9, 2026

Copy link
Copy Markdown

Description

Adds a stdlib-only sample under code/samples/python/scenarios/dispute/ showing what happens after an AP2 flow completes and the parties disagree, where the disagreement is not fraud.

The resolver reads only artifacts a completed flow already leaves behind — the checkout mandate hash, the payment mandate, both receipts, and the order record. It:

  1. verifies the authorization chain binds (payment_mandate.transaction_id and both receipts' reference against the closed checkout mandate's checkout_hash). A chain that does not bind is an authorization question, so the sample declines it and routes it to the network fraud process rather than deciding it;
  2. where the chain holds, decides performance per line;
  3. emits a determination with per-line outcomes and amounts, the factors considered, a signer-of-record slot, a loser-pays fee disposition, and a content-hash seal.

Scenario. A shopping agent completed a human-not-present purchase of 4 units under a signed Payment Mandate. The merchant issued Success receipts. The order record shows 1 of 4 units fulfilled and the merchant's own estimated_delivery window has passed with no adjustment.

Run it.

python code/samples/python/scenarios/dispute/resolve_dispute.py \
  code/samples/python/scenarios/dispute/dispute_record.json --now 2025-10-24

Line line_item_456 is overturned for 7500 minor units, fee paid by the merchant. Tamper with payment_mandate.transaction_id and the same command returns not_eligible: authorization_chain_broken with route: network fraud process.

Why it might be useful here. The point is narrow: the AP2 trail is sufficient evidence for a neutral third party to resolve non-fraud disputes without any data the protocol does not already emit. The sample names no provider and takes no position on who should run a resolver.

Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Follow the CONTRIBUTING Guide.
  • Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
  • Ensure the tests and linter pass — ruff passes under this repo's .ruff.toml (Google style, 80 columns) and cspell passes under .cspell.json. The sample runs clean from the repo root. The Lint Code Base job is red on a BIOME_LINT failure that predates this PR: the same failure appears on unrelated open PRs, and that job's FILTER_REGEX_EXCLUDE skips code/samples/, so it is not evaluating anything added here. Happy to rebase once it is green on main.
  • Appropriate docs were updated (if necessary) — the sample ships its own README; no existing docs needed changes.

Two notes for reviewers:

  • No API key and no third-party dependency; Python standard library only.
  • ATDRP and unassessable were added to .cspell/custom-words.txt, inserted in place without reordering the existing entries.
  • Happy to move, rename, or restructure the scenario directory if code/samples/python/scenarios/dispute/ is not where you would want it.

Fixes #N/A — new sample, no linked issue. 🦕

@maximusrufus
maximusrufus requested a review from a team as a code owner September 9, 2026 17:39
@google-cla

google-cla Bot commented Sep 9, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@maximusrufus
maximusrufus force-pushed the samples/dispute-scenario branch 3 times, most recently from 7296927 to c43411e Compare September 9, 2026 17:54
@maximusrufus

Copy link
Copy Markdown
Author

@googlebot I signed it!

Adds a stdlib-only sample under code/samples/python/scenarios/dispute that
shows what happens after an AP2 flow completes and the parties disagree, when
the disagreement is not fraud.

The resolver reads only artifacts a completed flow already leaves behind: the
checkout mandate hash, the payment mandate, both receipts, and the order
record. It verifies the authorization chain binds, and routes a broken chain
back to the network fraud process rather than deciding it. Where the chain
holds, it decides performance per line under a published policy and emits a
determination with per-line outcomes, the factors considered, a signer slot,
a loser-pays fee disposition, and a content-hash seal.

The point is narrow: the AP2 trail is sufficient evidence for a neutral third
party to resolve non-fraud disputes without any data the protocol does not
already emit. The sample names no provider and takes no position on who should
run a resolver.

No API key and no third-party dependency is required to run it.

Adds ATDRP and unassessable to the project spell-check dictionary.
@maximusrufus
maximusrufus force-pushed the samples/dispute-scenario branch from ea8d324 to b2c1c80 Compare September 9, 2026 21:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant