Repository navigation
feat(marine): port directory and marine-fuel history tools; canonical latest path (#125) - #175
Conversation
… latest path (#125) - opa_get_marine_ports: GET /v1/marine-ports (region/country/major filters) and GET /v1/marine-ports/{code} with prices collected in the last 24h. 404 names the unknown port, never the plan. - opa_get_marine_fuel_history: GET /v1/prices/marine-fuels/historical for one port and fuel, one row per assessment date (latest collection kept), high/low, and an explicit note when rows stop short of the requested window. Sends the full series code because a bare fuel_type returns an empty 200 (oilpriceapi-api#7774). 403 surfaces the API's own text. - opa_get_marine_fuels moves from the deprecated /v1/marine-fuels/latest alias to /v1/prices/marine-fuels/latest?limit=100. - Ledger v4, live-contract catalog entries, registry categories, README. GET /v1/prices/marine-fuels stays selected and not exposed. Part of #125 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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. Comment |
|
Reviewed canonical latest path, port directory and single-port behavior, daily history deduplication, bounded dates, entitlement and empty-data recovery. Corrected the obsolete 24-hour claim to the deployed seven-day observation window and added observed date/age/stale fields with a weekend regression test. Preserved futures-history integration and exact inventory of 40 registered / 36 read-only tools. Validation: 643 tests, build and packed protocol checks, pai-check TypeScript, and exact-provenance non-root Docker smoke; all current CI checks green. |
Part of #125 (selection 3 of the #77 capability ledger). Ships three of the four ledger rows plus the canonical-path move;
GET /v1/prices/marine-fuelsstays selected and not exposed (see "Not in this PR").What changes
opa_get_marine_ports(new)GET /v1/marine-ports,GET /v1/marine-ports/{port_code}region/country/major_onlyfilters, or one port by UN/LOCODE or name with prices collected in the last 24 h. A 404 names the unknown port and points at the directory, never the plan.opa_get_marine_fuel_history(new)GET /v1/prices/marine-fuels/historicalport_code(5-letter UN/LOCODE),fuel_typeenumVLSFO/MGO_05S/HFO_380/HFO_180,days1-365 (default 30). One row per assessment date (latest collection kept), high/low when currency and unit agree, explicit note when the earliest row is later than the requested window start.opa_get_marine_fuelsGET /v1/prices/marine-fuels/latest?limit=100/v1/marine-fuels/latest.limit=100is the API cap; default is 50 series rows.Ledger
ledgerVersion3 -> 4 with achangesentry: the three rows flip toexposed, theviaalias is dropped from the latest row, the family lists all three tools. Release notes should link ledger v4.Backend contract (oilpriceapi-api origin/main, read-only)
/v1/marine-ports*(V1::MarineFuelPortsController): authenticated, no feature gate; Rack::Attackmarine-fuel/apithrottle 30/min per token./v1/prices/marine-fuels/historical(V1::PricesController#marine_fuels_historical): 403{"error":"Historical marine fuel data requires a paid subscription"}whenplan == 'free'and no live trial;port_code+fuel_typerequired (400 otherwise);daysclamped 1-365;limit(1000)rows; Rack::Attackmarine-fuel/historical5/min per token.:marine_bunker_data. That feature gates/v1/bunker-fuels/*and/v1/maritime-fuels/*, not these routes.smoke:public-claimsrejects hard-coded rate and plan claims. The numbers are above.Two backend defects found while verifying:
fuel_type=VLSFOon history returns an empty 200. The tool sends the series codeVLSFO_SGSIN_USD, which matches exactly today and still works after a backend fix. Re-verified on OilpriceAPI/oilpriceapi-api#7774.days=365returns 1,000 rows covering only 68 dates, because the cap is spent on repeated collections.metadata.countcounts ports, not rows. Filed OilpriceAPI/oilpriceapi-api#9641. The tool de-duplicates per date and says when the window was cut short.Red / green
src/__tests__/marineWorkflows.test.tsagainst unchangedsrc/index.ts: 20 failed / 0 passed.energyPlugin.test.ts > cancels an upstream that stalls…, which this PR does not touch ([P2][test] energyPlugin 'cancels an upstream that stalls' times out intermittently (2/5 local runs on origin/main) #172).src/__tests__/fixtures/marineWorkflowsLive.tsare verbatim live payloads (366 lines). Source change is about 240 lines insrc/index.ts.Checks run locally
npm test: green, apart from the [P2][test] energyPlugin 'cancels an upstream that stalls' times out intermittently (2/5 local runs on origin/main) #172 flakenpm run buildandtsc --noEmit: clean, 38 tools in the manifestnpm run check:capability-ledger:OK capability ledger v4: 118 published operations … (40 exposed, 78 not exposed, 6 selected); 38 registered toolsnpm run generate:live-contractsandnpm run smoke:live-contract-matrix: passednpm run smoke:public-claims: passed, 76 surfacesLive verification (production, smoke key, 2026-10-15)
scripts/live-smoke.mjswith the real handlers:PASSEDforopa_get_marine_ports,opa_get_marine_fuel_historyandopa_get_marine_fuels(HTTP 200, formatter fields present). The runner's only failures are the write-contract tools it skips withoutSMOKE_WRITE_CONTRACTS=1.Direct handler calls against production:
opa_get_marine_ports {}: 8 ports (SGSIN, NLRTM, USHOU, AEFUJ, HKHKG, USLAX, BRSSZ, USNYC)opa_get_marine_ports {port:"Singapore"}: SGSIN detail and 3 prices from the last 24 hopa_get_marine_ports {port:"XXXXX"}:The API has no marine port "XXXXX" (HTTP 404)…opa_get_marine_fuel_history SGSIN VLSFO 7: 5 dates, High 917 / Low 889.5 USD metric_tonopa_get_marine_fuel_history SGSIN VLSFO 365: 68 dates from 1000 rows, with the earliest-assessment note (2026-07-27 vs 2025-10-15)opa_get_marine_fuel_history SGSIN HFO_180 30: empty, named as such and pointed at fuel services, no plan wordingopa_get_marine_fuels {port:"NLRTM"}on the canonical path: 3 pricesUnverified: the live 403 for a free account without a trial. No free key was available. That case is covered by reading the backend code and by a unit test on the API's verbatim error body.
Not in this PR
GET /v1/prices/marine-fuelsstaysselected. Live it is a paginated feed of the 100 most recent collections: 62 rows across 8 ports, several per fuel. That overlaps latest (one per series) and history (per-port series), so a separate tool adds little. It needs a decision: reclassify it asdeferred/aliasin the ledger, or expose it as a follow-up.energy_marine_fuelsfacade (src/energyPlugin.ts) still calls the/v1/marine-fuels/latestalias. It is a separate surface and was left unchanged.🤖 Generated with Claude Code