Skip to content

fix: correct futures latest/curve paths (404) + live CI tests (v0.9.1)#20

Merged
karlwaldman merged 3 commits into
mainfrom
fix/futures-paths-live-ci
Jun 21, 2026
Merged

fix: correct futures latest/curve paths (404) + live CI tests (v0.9.1)#20
karlwaldman merged 3 commits into
mainfrom
fix/futures-paths-live-ci

Conversation

@karlwaldman

Copy link
Copy Markdown
Member

The path bug

The published v0.9.0 SDK builds the wrong URL for futures latest:

  • FuturesContractFamily.latest() (e.g. client.futures.brent().latest()) built /v1/futures/{slug}/latest404.
  • The top-level client.futures.latest(code) passed the raw contract code (e.g. "BZ") straight into the path → /v1/futures/BZ404 (the API routes are slug-based, not code-based).

The correct futures API (confirmed live + against config/routes.rb lines ~377-452 and app/controllers/v1/futures_controller.rb):

  • latest = GET /v1/futures/{slug} — the bare slug, NO /latest suffix.
  • curve = /v1/futures/{slug}/curve; historical/ohlc/intraday/spreads/spread-history = /{slug}/... — these family paths were already correct and are unchanged.
  • There is no /v1/futures/latest?contract= route.

Valid slugs: ice-brent, ice-wti, ice-gasoil, natural-gas, ttf-gas, lng-jkm, eua-carbon, uk-carbon (+ continuous/brent, continuous/wti).

The fix

  • FuturesContractFamily.latest() → now hits /v1/futures/{slug}. Corrects all typed helpers (.brent(), .wti(), .gasoil(), .naturalGas(), .ttfGas(), .lngJkm(), .euaCarbon(), .ukCarbon()).
  • Top-level client.futures.latest(contract) → resolves a contract code or a family slug to the slug, then hits /v1/futures/{slug}. Throws a clear ValidationError for unknown inputs.
  • Added resolveFuturesFamilySlug() and a QS alias for ICE Gasoil.
  • Updated doc comments that wrongly stated families support /latest.

Code → slug mapping

Code Slug
BZ ice-brent
CL ice-wti
G / QS ice-gasoil
NG natural-gas
TTF ttf-gas
JKM lng-jkm
EUA eua-carbon
UKA uk-carbon

(Family slugs are also accepted directly, case-insensitively.)

Live CI tests

  • tests/live/futures.test.ts — hits the REAL API using process.env.OILPRICEAPI_TEST_KEY and asserts client.futures.brent().latest() and the top-level client.futures.latest('BZ' / 'CL') return 200 + a sane price shape. Skips gracefully when the key env is absent (offline / forks). Requests are spaced (~1.1s) to respect the 1 req/sec rate limit, kept to a handful of calls to avoid 429s.
  • .github/workflows/live-tests.yml — new job runs npm run test:live on push/PR to main with OILPRICEAPI_TEST_KEY: ${{ secrets.OILPRICEAPI_TEST_KEY }}. Gated so it only runs the live step when the secret is present (if: ${{ secrets.OILPRICEAPI_TEST_KEY != '' }}) and the job is skipped for external-fork PRs, so forks are never blocked.

Version

Bumped package.json + src/version.ts 0.9.0 → 0.9.1.

Gates

  • npx tsc --noEmit — clean
  • npm test — 399 passing (offline unit suite)
  • npm run build — clean
  • npm run lint — 0 errors (pre-existing warnings only, none in changed files)
  • npm run test:live — skips gracefully locally (no key); will run against prod in CI via the secret

🤖 Generated with Claude Code

The futures `latest` endpoint is served from the bare slug path
`GET /v1/futures/{slug}` (no `/latest` suffix). The published v0.9.0 SDK
built `/v1/futures/{slug}/latest`, which 404s.

Fixes:
- FuturesContractFamily.latest() now hits `/v1/futures/{slug}` instead of
  `/v1/futures/{slug}/latest`. This corrects all typed helpers
  (`.brent().latest()`, `.gasoil().latest()`, etc.).
- Top-level `client.futures.latest(code)` now resolves a contract code or
  family slug to its slug and hits `/v1/futures/{slug}`. Previously it
  passed the raw code (e.g. "BZ") straight into the path -> 404.
- Added `resolveFuturesFamilySlug()` + a `QS` alias for ICE Gasoil.
  Code -> slug: BZ->ice-brent, CL->ice-wti, G/QS->ice-gasoil,
  NG->natural-gas, TTF->ttf-gas, JKM->lng-jkm, EUA->eua-carbon,
  UKA->uk-carbon.
- Updated doc comments that wrongly claimed families support `/latest`.

curve/historical/ohlc/intraday/spreads/spread-history family paths were
already correct and are unchanged.

Tests + CI:
- New live test (tests/live/futures.test.ts) hits the REAL API via
  OILPRICEAPI_TEST_KEY and asserts brent().latest() + top-level latest()
  return 200 + a sane price. Skips gracefully when the key is absent;
  spaces requests to respect the 1 req/sec limit.
- New live-tests.yml workflow runs `npm run test:live` on push/PR to main,
  gated on the OILPRICEAPI_TEST_KEY secret so forks never fail.
- Updated unit tests to assert the corrected paths + code->slug mapping.

Bumped 0.9.0 -> 0.9.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@karlwaldman, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 29 minutes and 57 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1d70401c-2daa-4526-9336-16e44a3bf618

📥 Commits

Reviewing files that changed from the base of the PR and between 07ab00c and 7ffae48.

📒 Files selected for processing (7)
  • .github/workflows/live-tests.yml
  • package.json
  • src/resources/futures.ts
  • src/version.ts
  • tests/live/futures.test.ts
  • tests/resources/futures-family.test.ts
  • tests/resources/futures.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/futures-paths-live-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

karlwaldman and others added 2 commits June 21, 2026 13:07
…a (v0.9.1)

GET /v1/futures/{slug} returns a TOP-LEVEL object (no {status,data}
envelope); the latest price lives at front_month.last_price with the
full term structure in contracts[]. The FuturesPrice type modeled a
flat {contract, price, currency} shape that did not match reality, so
the LIVE CI test failed even though request()'s as-is fallback already
returned the real object.

- FuturesPrice: model real top-level shape (commodity, source,
  updated_at, settlement_date, front_month, contracts[], metadata).
  Legacy flat fields kept optional for backward compatibility.
- Add FuturesContractMonth interface (code, contract_month, last_price,
  currency, open/close/high/low).
- FuturesCurveData: make `curve` optional and add `error`/`date` so the
  documented no-data response ({error:"No futures data available for
  curve analysis", date}) is a valid, typed state rather than a failure.
- Live test: assert front_month.last_price is a sane number; make
  curve() tolerant of EITHER curve data OR the no-data response. Kept to
  3 calls spaced >=1.1s.
- Mock unit tests: latest() now uses the real top-level shape; added a
  curve() no-data case.

Gates: tsc --noEmit clean, 400 tests pass, build OK, lint 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ence)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@karlwaldman karlwaldman merged commit 20f44d1 into main Jun 21, 2026
1 check passed
@karlwaldman karlwaldman deleted the fix/futures-paths-live-ci branch June 21, 2026 17:13
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