Skip to content

feat(ledger): BCB PTAX exchange-rate provider - #355

Merged
sonikro merged 4 commits into
feat/ledger-corefrom
feat/ledger-fx
Oct 16, 2026
Merged

sonikro merged 4 commits into
feat/ledger-corefrom
feat/ledger-fx

Conversation

@sonikro

@sonikro sonikro commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

Stack 2/4 — BCB PTAX exchange rates (base: feat/ledger-core)

The exchange-rate provider the ledger uses to convert USD into BRL.

What this PR adds

  • BcbPtaxProvider: the BCB Olinda PTAX provider, with a 7-day step-back over non-publishing
    days, a per-day cache, an abort timeout, and JSON/response guards.
  • Exported from the fx barrel of @tf2qs/providers.

The fix this PR carries

The provider originally queried CotacaoMoedaDia, which returns five bulletins for a business
day with the opening rate first, and took the first row. Every USD donation and the bot
infrastructure cost were therefore converted at the opening rate while being recorded as PTAX.
It now queries CotacaoDolarDia, which returns exactly the closing bulletin. Verified against
the live endpoint for 2026-10-14: the old operation returned five rows starting at 5.04620, the
new one returns the single closing row at 5.04410, identical to the last row of the old response.

The date literal must stay MM-DD-YYYY: the ISO form returns HTTP 200 with an empty value
array, which is why the fallback walk never surfaced the problem.

Testing

  • CI=true npx vitest run → 105 files, 756 tests, 0 failures.
  • npm run build:backend → clean.
  • The suite now runs with msw's onUnhandledRequest: "error", so reverting to the wrong
    operation fails the tests instead of passing them against the live API.

Notes

  • This PR has no CI of its own: release.yaml only triggers pull_request on main, and this
    branch's base is another feature branch. It was verified locally at the stack tip.
  • quotedAt is parsed from the BCB timestamp without a zone, so it lands in host-local time.
    Nothing consumes it; fixing it is a follow-up.

Stack

Previous: #354 (feat/ledger-core). Next: #356 (feat/ledger-commands → this branch).

@sonikro
sonikro added this pull request to stack #358 October 13, 2026 00:29
@sonikro
sonikro force-pushed the feat/ledger-fx branch 3 times, most recently from adb6d02 to 5afa59d Compare October 15, 2026 12:55
Follow the repository convention for a module whose main export is a class,
and keep the export path in the fx barrel in step. The exported
BcbPtaxProvider symbol is unchanged, so consumers are unaffected.
The provider queried CotacaoMoedaDia, which returns five bulletins for a
business day with the opening rate first, and took values[0]. Every USD
donation and the bot infrastructure cost were therefore converted at the
opening rate while being recorded as the PTAX rate.

Query CotacaoDolarDia instead, which returns exactly the closing bulletin
row. Verified against the live endpoint for 2026-10-14: the old operation
returned five rows starting at 5.04620, the new one returns the single
closing row at 5.04410, identical to the last row of the old response.

The date literal stays MM-DD-YYYY: the ISO form returns HTTP 200 with an
empty value array, which is why the fallback walk never surfaced the
problem.
The msw matchers are URL-specific, so a provider that reverted to the wrong
BCB operation would not match any handler and the request would pass through
to the live endpoint, letting the suite pass against the real API. Make an
unhandled request an error.
@sonikro
sonikro marked this pull request as ready for review October 15, 2026 13:52
@sonikro
sonikro merged commit e6e0195 into main Oct 16, 2026
10 checks passed
@sonikro
sonikro deleted the feat/ledger-fx branch October 16, 2026 23:58
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