Files
claude bb4219da87
CI / test (push) Successful in 18s
CI / build-push (push) Successful in 5s
feat: nutrient_cost tool — cheapest fertilizer per lb of N/P/K (#1)
Co-authored-by: claude <claude@jpaul.io>
Co-committed-by: claude <claude@jpaul.io>
2026-06-04 15:58:59 -04:00

434 lines
18 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Markdown formatter tests — no network, just JSON-in / markdown-out."""
from __future__ import annotations
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from ag_bids_mcp import format as fmt
def test_fmt_best_with_winner():
payload = {
"commodity": "corn", "today": "2026-05-20",
"best": {
"source_name": "Mercer Landmark — St Henry",
"delivery": "May 2026",
"bid_cents": 491, "basis_cents": 33,
"futures_contract": "ZCK26",
"fetched_at": "2026-05-20T15:00:00+00:00",
},
}
out = fmt.fmt_best("corn", payload)
assert "Mercer Landmark — St Henry" in out
assert "$4.9100/bu" in out
assert "May 2026" in out
assert "+0.33" in out
def test_fmt_best_no_winner():
payload = {"commodity": "wheat", "today": "2026-05-20", "best": None}
out = fmt.fmt_best("wheat", payload)
assert "No current-month" in out
assert "wheat" in out
def test_fmt_best_with_location_shows_distance():
payload = {
"commodity": "corn", "today": "2026-05-20",
"center": {"lat": 40.78, "lng": -83.81, "zip": "45810", "source": "zip"},
"radius_miles": 50.0,
"best": {
"source_name": "Heritage Cooperative — Ada", "city": "Ada", "state": "OH",
"delivery": "May 2026", "bid_cents": 486, "basis_cents": 20,
"futures_contract": "ZCN26", "distance_miles": 2.3,
"fetched_at": "2026-05-20T15:00:00+00:00",
},
}
out = fmt.fmt_best("corn", payload)
assert "(Ada, OH)" in out
assert "2.3 mi" in out
assert "within 50 mi of ZIP 45810" in out
def test_fmt_best_out_of_range_reports_nearest():
payload = {
"commodity": "corn", "today": "2026-05-20", "best": None,
"center": {"lat": 42.0, "lng": -93.6, "zip": "50010", "source": "zip"},
"radius_miles": 50.0,
"nearest": {"source_name": "Heritage Cooperative — Ada", "city": "Ada",
"state": "OH", "distance_miles": 513.5},
}
out = fmt.fmt_best("corn", payload)
assert "No current-month corn bids within 50 mi of ZIP 50010" in out
assert "Nearest tracked elevator" in out
assert "513.5 mi" in out
def test_fmt_latest_with_location_adds_distance_column():
payload = {
"center": {"lat": 40.78, "lng": -83.81, "zip": "45810", "source": "zip"},
"radius_miles": 50.0,
"rows": [
{"source_name": "Heritage Cooperative — Ada", "commodity": "corn",
"display_name": "Corn", "commodity_kind": "grain", "delivery": "May 2026",
"bid_cents": 486, "basis_cents": 20, "futures_contract": "ZCN26",
"distance_miles": 2.3, "fetched_at": "2026-05-20T15:00:00+00:00"},
],
}
out = fmt.fmt_latest(payload)
assert "Distance" in out and "2.3 mi" in out
assert "within 50 mi of ZIP 45810" in out
def test_fmt_latest_location_no_rows():
payload = {"center": {"zip": "50010", "source": "zip"}, "radius_miles": 50.0, "rows": []}
out = fmt.fmt_latest(payload)
assert "No sources within 50 mi of ZIP 50010" in out
def test_fmt_futures_with_changes():
payload = {
"commodity": "corn", "delivery": "Jul 2026", "contract": "ZCN26",
"symbol": "ZC",
"quote": {
"settle_date": "2026-05-29", "open_cents": 461, "last_cents": 455,
"prev_close_cents": 460, "change_since_open_cents": -6,
"change_on_day_cents": -5, "fetched_at": "2026-05-29T18:00:00+00:00",
},
}
out = fmt.fmt_futures(payload)
assert "ZCN26" in out and "Jul 2026" in out
assert "$4.5500" in out # last
assert "$4.6100" in out # open
assert "▼ -0.06" in out # change since open
assert "▼ -0.05" in out # change on day
def test_fmt_futures_no_open_yet():
payload = {
"commodity": "soy", "delivery": None, "contract": "continuous",
"symbol": "ZS=F",
"quote": {
"settle_date": "2026-05-29", "open_cents": None, "last_cents": 1180,
"prev_close_cents": 1177, "change_since_open_cents": None,
"change_on_day_cents": 3, "fetched_at": "2026-05-29T18:00:00+00:00",
},
}
out = fmt.fmt_futures(payload)
assert "continuous nearby" in out
assert "no open captured yet" in out
assert "▲ +0.03" in out # change on day still shown
def test_fmt_futures_no_quote():
out = fmt.fmt_futures({"commodity": "wheat", "delivery": None,
"contract": "continuous", "quote": None})
assert "No futures quote on file" in out
def test_fmt_price_trend():
payload = {"commodity": "corn", "geo": "OH", "unit": "$/bu",
"source": "USDA NASS Quick Stats",
"trend": {"period": "2026-04-01", "value_cents": 468,
"prev_cents": 459, "change_cents": 9, "change_pct": 2.0,
"yoy_cents": 480, "yoy_change_cents": -12, "yoy_pct": -2.5,
"seasonal": {"normal_cents": 435, "median_cents": 430,
"min_cents": 400, "max_cents": 480,
"percentile": 75, "vs_normal_pct": 7.6,
"sample_years": 4},
"recent_direction": "up", "baseline_years": 10, "points": 120}}
out = fmt.fmt_price_trend(payload)
assert "corn — OH" in out
assert "$4.68/bu" in out
assert "+$0.09" in out and "+2.0%" in out # MoM change
assert "$0.12" in out and "2.5%" in out # YoY
assert "75th pct" in out
def test_fmt_price_trend_empty():
out = fmt.fmt_price_trend({"commodity": "wheat", "geo": "US", "unit": "$/bu", "trend": None})
assert "No data on file" in out
def test_fmt_price_series():
payload = {"commodity": "corn", "geo": "US", "unit": "$/bu", "count": 2,
"series": [{"period": "2026-03-01", "value_cents": 459},
{"period": "2026-04-01", "value_cents": 468}]}
out = fmt.fmt_price_series(payload)
assert "Mar 2026" in out and "$4.59/bu" in out
assert "Apr 2026" in out and "$4.68/bu" in out
def test_fmt_price_trend_diesel_units():
payload = {"commodity": "diesel", "geo": "US", "unit": "$/gal", "source": "EIA",
"trend": {"period": "2026-05-25", "value_cents": 552, "prev_cents": 560,
"change_cents": -8, "change_pct": -1.4, "yoy_cents": None,
"yoy_change_cents": None, "yoy_pct": None, "seasonal": None,
"recent_direction": "down", "baseline_years": 10, "points": 200}}
out = fmt.fmt_price_trend(payload, label="retail diesel")
assert "$5.520/gal" in out # 3-decimal $/gal formatting
def test_fmt_input_cost_payload_shape():
# Input-cost payload uses item/label and has no geo.
payload = {"item": "diesel", "label": "retail diesel", "unit": "$/gal", "source": "EIA",
"trend": {"period": "2026-05-25", "value_cents": 552, "prev_cents": 560,
"change_cents": -8, "change_pct": -1.4, "yoy_cents": 349,
"yoy_change_cents": 203, "yoy_pct": 58.2, "seasonal": None,
"recent_direction": "down", "baseline_years": 10, "points": 1680}}
out = fmt.fmt_price_trend(payload)
assert "diesel — retail diesel" in out # item/label header, no geo segment
assert "$5.520/gal" in out
assert "+58.2%" in out # YoY surfaced
def test_fmt_input_cost_fertilizer_ton_and_region():
# Fertilizer payload carries item + geo (region) + $/ton.
payload = {"item": "urea", "geo": "Cornbelt", "label": "urea", "unit": "$/ton",
"source": "USDA AgTransport",
"trend": {"period": "2026-03-01", "value_cents": 69812, "prev_cents": 51812,
"change_cents": 18000, "change_pct": 34.7, "yoy_cents": 45500,
"yoy_change_cents": 24312, "yoy_pct": 53.4, "seasonal": None,
"recent_direction": "up", "baseline_years": 10, "points": 39}}
out = fmt.fmt_price_trend(payload)
assert "urea — Cornbelt — urea" in out # item, region, label all present
assert "$698.12/ton" in out
assert "USDA AgTransport" in out
assert "Mar 2026" in out # monthly period rendered as month
def test_fmt_inputs_lime_table():
payload = {
"product": "lime", "count": 2,
"rows": [
{"source_name": "Bob's Lime Quote", "commodity": "lime",
"display_name": "Lime", "delivery": "spot",
"bid_cents": 42000, "commodity_kind": "fertilizer",
"fetched_at": "2026-05-20T15:00:00+00:00"},
{"source_name": "Coop X", "commodity": "lime",
"display_name": "Lime", "delivery": "spot",
"bid_cents": 45500, "commodity_kind": "fertilizer",
"fetched_at": "2026-05-20T15:01:00+00:00"},
],
}
out = fmt.fmt_inputs(payload)
assert "LIME prices" in out
assert "$420.00" in out
assert "$455.00" in out
assert "Bob's Lime Quote" in out
def test_fmt_inputs_empty():
out = fmt.fmt_inputs({"product": "lime", "rows": []})
assert "No lime prices on file." in out
def test_fmt_latest_table_picks_correct_unit():
payload = {"count": 2, "rows": [
{"source_name": "Bambauer", "commodity": "corn",
"display_name": "Corn", "delivery": "May 2026",
"bid_cents": 458, "basis_cents": 2, "commodity_kind": "grain",
"futures_contract": "ZCN26", "fetched_at": "2026-05-20T15:00:00+00:00"},
{"source_name": "Coop X", "commodity": "lime",
"display_name": "Lime", "delivery": "spot",
"bid_cents": 42000, "basis_cents": None, "commodity_kind": "fertilizer",
"futures_contract": None, "fetched_at": "2026-05-20T15:00:00+00:00"},
]}
out = fmt.fmt_latest(payload)
assert "$4.5800" in out # grain in /bu (4 decimals)
assert "$420.00" in out # fertilizer in /ton (2 decimals)
def test_fmt_history_with_trend_arrow():
payload = {
"commodity": "corn", "days": 7,
"rows": [
{"source_name": "Andersons", "delivery": "May 2026",
"bid_cents": 480, "basis_cents": 25,
"fetched_at": "2026-05-15T15:00:00+00:00"},
{"source_name": "Andersons", "delivery": "May 2026",
"bid_cents": 496, "basis_cents": 30,
"fetched_at": "2026-05-20T15:00:00+00:00"},
],
}
out = fmt.fmt_history(payload)
assert "▲" in out
assert "$4.8000" in out
assert "$4.9600" in out
# Basis trend is now surfaced in the summary line too.
assert "basis +0.25 → +0.30" in out
def _history_multi():
return {
"commodity": None, "days": 7,
"rows": [
{"source_name": "Minster", "commodity": "corn", "delivery": "Jul 2026",
"bid_cents": 461, "basis_cents": 11, "futures_cents": 450,
"fetched_at": "2026-05-23T15:00:00+00:00"},
{"source_name": "Minster", "commodity": "corn", "delivery": "Jul 2026",
"bid_cents": 464, "basis_cents": 14, "futures_cents": 450,
"fetched_at": "2026-05-29T15:00:00+00:00"},
{"source_name": "Minster", "commodity": "soy", "delivery": "Nov 2026",
"bid_cents": 1145, "basis_cents": -50, "futures_cents": 1195,
"fetched_at": "2026-05-23T15:00:00+00:00"},
{"source_name": "Minster", "commodity": "soy", "delivery": "Nov 2026",
"bid_cents": 1148, "basis_cents": -45, "futures_cents": 1193,
"fetched_at": "2026-05-29T15:00:00+00:00"},
],
}
def test_fmt_history_spans_crops_and_shows_basis_futures():
out = fmt.fmt_history(_history_multi())
# No commodity filter → "all crops" scope, both crops present.
assert "all crops" in out
assert "corn" in out and "soy" in out
# Futures column populated from futures_cents.
assert "$4.5000" in out
# Basis movement annotated per series.
assert "+0.11 → +0.14" in out
assert "-0.50 → -0.45" in out
def test_fmt_basis_movement_aggregates_per_crop():
out = fmt.fmt_basis_movement(_history_multi())
assert "Basis movement" in out
# corn basis 0.11 → 0.14 (stronger), soy -0.50 → -0.45 (stronger)
assert "**corn**" in out and "**soy**" in out
assert "stronger" in out
assert "1 elevators, 1 series" in out
def test_fmt_basis_movement_skips_non_grain_and_nulls():
payload = {"commodity": None, "days": 7, "rows": [
{"source_name": "Coop", "commodity": "lime", "delivery": "spot",
"bid_cents": 42000, "basis_cents": None, "fetched_at": "2026-05-23T15:00:00+00:00"},
]}
out = fmt.fmt_basis_movement(payload)
assert "No grain basis samples" in out
def test_fmt_basis_detail_per_series():
out = fmt.fmt_basis_detail(_history_multi())
assert "Basis movement by elevator" in out
# One row per (crop, elevator, delivery)
assert "| corn | Minster | Jul 2026 |" in out
assert "| soy | Minster | Nov 2026 |" in out
assert "weaker" not in out # both strengthened in this fixture
assert "stronger" in out
def test_fmt_sources_table():
payload = {"sources": [
{"id": 1, "name": "Test Elev", "kind": "elevator",
"city": "Ada", "state": "OH", "zip": "45810",
"last_success_at": "2026-05-20T14:55:00+00:00",
"consecutive_failures": 0, "last_error": None},
]}
out = fmt.fmt_sources(payload)
assert "Test Elev" in out
assert "elevator" in out
assert "Ada, OH 45810" in out # location column
def test_fmt_health_buckets():
payload = {"sources": [
{"name": "Healthy", "kind": "elevator",
"last_success_at": "2026-05-20T14:55:00+00:00",
"consecutive_failures": 0, "last_error": None},
{"name": "Stale", "kind": "elevator",
"last_success_at": None,
"consecutive_failures": 0, "last_error": None},
{"name": "Down", "kind": "elevator",
"last_success_at": "2026-05-15T14:55:00+00:00",
"consecutive_failures": 5, "last_error": "boom"},
]}
out = fmt.fmt_health(payload)
assert "Healthy: **1**" in out
assert "Stale (never succeeded): **1**" in out
assert "Down" in out and "**1**" in out
# Down section lists boom
assert "boom" in out
def test_fmt_deliveries():
out = fmt.fmt_deliveries({"commodity": "corn",
"deliveries": ["May 2026", "Jul 2026"]})
assert "- May 2026" in out
assert "- Jul 2026" in out
def test_fmt_commodities_lists_all_six():
out = fmt.fmt_commodities()
for name in ("corn", "soy", "wheat", "map", "potash", "lime"):
assert name in out.lower()
def test_fmt_summary_includes_best_for_today():
payload = {
"today": "2026-05-20", "prev_trading_day": "2026-05-19",
"commodities": [
{"symbol": "corn", "display_name": "Corn",
"futures": {"contract": "ZC=F", "today_last_cents": 458,
"prev_close_cents": 455, "change_cents": 3},
"best_for_today": {
"source_name": "Mercer Landmark — St Henry",
"delivery": "May 2026", "bid_cents": 491, "basis_cents": 33,
}},
{"symbol": "soy", "display_name": "Soybeans",
"futures": {"contract": "ZS=F", "today_last_cents": 1180,
"prev_close_cents": 1177, "change_cents": 3},
"best_for_today": None},
],
}
out = fmt.fmt_summary(payload)
assert "Corn" in out and "Soybeans" in out
assert "Mercer Landmark — St Henry" in out
assert "$4.5800" in out # corn last
assert "No current-month local bid posted" in out # soy fallback
def test_fmt_nutrient_cost():
payload = {
"geo": "Cornbelt",
"source": "USDA AgTransport",
"products": [
{"item": "anhydrous", "label": "anhydrous ammonia", "unit": "$/ton",
"geo": "Cornbelt", "period": "2026-03-01", "price_cents_per_ton": 88062,
"analysis": {"grade": "82-0-0", "grade_assumed": False},
"cost_per_lb": {"n": 54, "p2o5": None, "k2o": None}},
{"item": "urea", "label": "urea", "unit": "$/ton", "geo": "Cornbelt",
"period": "2026-03-01", "price_cents_per_ton": 69812,
"analysis": {"grade": "46-0-0", "grade_assumed": False},
"cost_per_lb": {"n": 76, "p2o5": None, "k2o": None}},
{"item": "uan", "label": "UAN (28-32%)", "unit": "$/ton", "geo": "Cornbelt",
"period": "2026-03-01", "price_cents_per_ton": 47612,
"analysis": {"grade": "32-0-0", "grade_assumed": True},
"cost_per_lb": {"n": 74, "p2o5": None, "k2o": None}},
{"item": "potash", "label": "potash (0-0-60)", "unit": "$/ton",
"geo": "Cornbelt", "period": "2026-03-01", "price_cents_per_ton": 35938,
"analysis": {"grade": "0-0-60", "grade_assumed": False},
"cost_per_lb": {"n": None, "p2o5": None, "k2o": 30}},
],
"cheapest": {"n": "anhydrous", "p2o5": None, "k2o": "potash"},
}
out = fmt.fmt_nutrient_cost(payload)
assert "Cornbelt" in out
assert "Cheapest Nitrogen (N):** anhydrous ammonia at $0.54/lb" in out
assert "Cheapest Potash (K₂O):** potash (0-0-60) at $0.30/lb" in out
# anhydrous (cheapest N) sorts above urea in the table
assert out.index("anhydrous ammonia |") < out.index("| urea |")
# UAN grade-assumed marker + footnote
assert "32-0-0*" in out
assert "UAN grade assumed 32-0-0" in out
# potash supplies no N -> em-dash in the N column
assert "—" in out
def test_fmt_nutrient_cost_empty():
assert "No data on file" in fmt.fmt_nutrient_cost({"geo": "Cornbelt", "products": []})