Skip to content

fix(customers): EstimatedAnnualRevenue top band has an extra zero - #66

Merged
ericviana merged 1 commit into
mainfrom
eric/fix-estimated-annual-revenue
Aug 4, 2026
Merged

ericviana merged 1 commit into
mainfrom
eric/fix-estimated-annual-revenue

Conversation

@ericviana

Copy link
Copy Markdown
Member

Summary

Fixes a fifth type-surface defect, found by manual review after #64 (which fixed four others) had already been merged and released as 3.2.0 -- this is a separate PR against current main, not an addition to #64.

EstimatedAnnualRevenue in src/blindpay/resources/customers/customers.py ended with "2500000000_plus" (2.5 billion, an extra zero). The spec's enum on CreateCustomerIn, UpdateCustomerIn, CustomerOut and both customer webhook schemas is:

["0_99999", "100000_999999", "1000000_9999999", "10000000_49999999", "50000000_249999999", "250000000_plus"]

250000000_plus (250 million) is the only coherent reading: the band directly below it tops out at 249999999, so the top band has to start at 250000000 to avoid a gap. A business customer selecting the top annual-revenue band sends a value the API rejects -- the same class of live defect as BankAccountType/account_type in #64. node, go, php and swift have the identical typo; those are being handled separately.

Why sync.py --audit-types / --check did not catch this

They did not compare EstimatedAnnualRevenue against the spec at all -- it was never added to .api-sync/spec-map.json's enums list in #58's Phase A bootstrap. That list covers 17 shared, broadly-reused Literals (Network, StablecoinToken, BankAccountType, etc.); it does not cover the long tail of customer-domain-specific enums customers.py declares on its own (CustomerBusinessType, BusinessIndustry, SourceOfWealth, TaxType, AmlStatus, ProofOfAddressDocType, PurposeOfTransactions, SourceOfFundsDocType, and roughly a dozen more -- none mapped).

This is a map-coverage gap, not a comparison-logic flaw: reconcile_enums only ever inspects what spec-map.json lists, so an unmapped Literal is invisible to it regardless of whether it has one extra member, one missing member, or both at once (which is exactly this case: the SDK has 2500000000_plus, which the spec lacks, AND lacks 250000000_plus, which the spec has). Not redesigning or expanding map coverage in this PR -- flagging it as a real, separate gap worth a dedicated pass (adding the ~16 customer-domain enums to spec-map.json) later.

Tests

Added TestEstimatedAnnualRevenueTopBandIsCorrect to tests/test_types.py (the file #64 introduced): an explicit EstimatedAnnualRevenue-annotated literal proving "250000000_plus" type-checks (pyright/mypy both run over tests/). No existing fixture referenced the old value, so nothing else needed updating.

Proof

$ uv sync --group dev --group test
... blindpay==3.2.0 (editable, matches current main)

$ uv run ruff format --check .
72 files already formatted

$ uv run ruff check .
All checks passed!

$ uv run pyright
0 errors, 0 warnings, 0 informations

$ uv run mypy .
Success: no issues found in 69 source files

$ uv run pytest --tb=short -q
...
216 passed in 0.99s

$ python3 .api-sync/check_contract.py
Direction A and B: PASSED.

$ python3 .api-sync/sync.py --validate-map
Map validity: OK

$ python3 .api-sync/sync.py --check
(silent, exit 0)

Version bump

fix: -- a single Literal value correction, patch-level (unlike #64's feat:, this doesn't add or restructure any type shape, just corrects one wrong string).

Per the working rules: fresh branch off current main (post #64/3.2.0), not merged, opening for review and stopping here.

https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs

Literal ended with "2500000000_plus" (2.5 billion). The spec's enum on
CreateCustomerIn, UpdateCustomerIn, CustomerOut and both customer webhook
schemas is:
["0_99999", "100000_999999", "1000000_9999999", "10000000_49999999",
 "50000000_249999999", "250000000_plus"]

250000000_plus (250 million) is the only coherent reading: the band directly
below it tops out at 249999999, so the top band has to start at 250000000.
A business customer selecting the top revenue band sends a value the API
rejects -- the same class of live defect as account_type/BankAccountType
(#64).

Why .api-sync/sync.py's enum reconciliation did not catch this on its own:
it did not compare at all. EstimatedAnnualRevenue was never added to
spec-map.json's `enums` list during Phase A (#58) -- that list covers 17
shared, broadly-reused Literals, not the long tail of customer-domain-
specific ones customers.py declares (CustomerBusinessType, BusinessIndustry,
SourceOfWealth, TaxType, AmlStatus, ProofOfAddressDocType,
PurposeOfTransactions, SourceOfFundsDocType, and others -- roughly 15 more
Literals with no map entry at all). This is a map-coverage gap, not a
comparison-logic flaw: reconcile_enums only ever inspects what
spec-map.json lists, so an unmapped Literal is invisible to it regardless of
whether it has one extra member, one missing member, or both. Not
redesigning or expanding map coverage in this PR -- noting it as a real,
separate gap for a future pass.

Claude-Session: https://claude.ai/code/session_01F1stiNzuNtJXoXtiW9ZCbs
@BernardoSM

Copy link
Copy Markdown
Collaborator

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@ericviana
ericviana merged commit 09892d9 into main Aug 4, 2026
8 checks passed
@ericviana
ericviana deleted the eric/fix-estimated-annual-revenue branch August 4, 2026 00:46
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.

2 participants