Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

SDK constraints: budget limit truncates floats (0.29 -> 28 cents), execution_date compared as text, negative amounts pass

Open Beginner friendly
#388 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
75/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
payments

Research direction

Locate the constraint logic in the ap2.sdk.constraints module (likely ap2/sdk/constraints.py) containing BudgetEvaluator, ExecutionDateEvaluator and Amount. Fix float truncation with Decimal, parse dates to timezone-aware datetimes, and add ge=0 to Amount.amount. Run constraints_tests.py and constraints_line_items_tests.py; done when all tests pass and the three reported cases match the spec.

Written by the indexing model from the issue text.

Description

Hi, I am building an independent implementation of the payment-mandate constraint check (Rust and TypeScript: https://github.com/kennzyoguh-lang/kaldrix-x402-guard) and compared it with ap2.sdk.constraints.check_payment_constraints on 327 generated cases (checked at e1ea56d, 29 April 2026). The SDK's own constraints_tests.py and constraints_line_items_tests.py pass here (62 tests). Our verdicts agree with the SDK on about 310 of the cases; the comparison also found one place where my own code was laxer than the SDK (a pre-set payment_instrument compared by id alone), which is fixed on our side. The remaining differences come down to the three behaviours below, where the SDK looks different from the specification text.

Cases, generator and a reproduction script: https://github.com/kennzyoguh-lang/kaldrix-x402-guard/tree/main/tests/vectors (repro_reference_findings.py runs against a checkout of this repo).

1. BudgetEvaluator: int(self.constraint.max * 100) loses a cent

The spec (Budget, Evaluation) says the requested amount plus the total of previous amounts MUST be less than or equal to max. The budget is in whole currency units and amounts are in minor units, and the conversion truncates a float product: int(0.29 * 100) is 28 and int(1.15 * 100) is 114. A payment equal to the budget is refused:

run([{'type': 'payment.budget', 'max': 0.29, 'currency': 'USD'}], closed(amount=29), MandateContext(total_amount=0, total_uses=0))
# ['Cumulative spend 29 exceeds budget limit 28 (past spend: 0)']

Suggestion: convert with Decimal(str(max)) * 100, or round before truncating.

2. ExecutionDateEvaluator compares the dates as strings

exec_date < self.constraint.not_before and exec_date > self.constraint.not_after compare str values. The spec says the execution date MUST be later than or equal to not_before and earlier than or equal to not_after, which is about instants. With not_after = 2026-11-30T23:59:59Z:

  • 2026-11-30T23:30:00-05:00 (that is 04:30Z on 1 December, after the window) gives no violation.
  • 2026-12-01T00:30:00+01:00 (that is 23:30Z on 30 November, inside the window) gives 'is after allowed window'.
  • With not_before = 2026-11-30T00:00:00Z, 2026-11-30 12:00:00 (space instead of T) gives 'is before allowed window'.

Suggestion: parse both sides to timezone-aware datetimes before comparing, and say what a date-only value means (the spec examples use both forms).

3. Negative amounts are accepted

Amount.amount is an int with no lower bound. An amount_range with no min accepts a payment of -5, and BudgetEvaluator adds the amount to the running total, so a negative amount also passes a budget that is already used up. Suggestion: ge=0 on Amount.amount, or an explicit check in check_payment_constraints.

A question rather than a bug: agent_recurrence.frequency

AgentRecurrenceEvaluator only checks max_occurrences. frequency is never evaluated and calculate_period_start is not called anywhere (it also has no case for BIWEEKLY or QUARTERLY), while the spec says the constraint holds only if the payment is 'sufficiently separated in time from the previous presentation to meet the frequency definition'. Is that intentional for 0.2, or planned? We copied the SDK's behaviour and say so, rather than guess.

I am not affiliated with Google or the FIDO Alliance, and this is not an endorsement claim in either direction. Happy to send a pull request for any of these if that would help.

Dominant language
Python
Stars
3.2k
Forks
514
PR merge metrics
No merged PRs in 30d

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from google-agentic-commerce/AP2

All issues in google-agentic-commerce/AP2

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.