- puga/network.py + tools/network.py: model a multi-base chain (e.g. mine LST at one base, ship it, consume it at another). Simulates each base independently, nets a transferred material's producer-surplus against consumer-need, charges real freight only on what's moved, cm_free for a founding covered by a Core Module Kit. Worked example in plans/chains/. - puga/saturation.py: real price-band filtering. FIO's order_book NarrowPriceBandLow/High and WidePriceBandLow/High match APEX's own displayed Price Band exactly (verified live) - an order outside it is a stale artifact, not just uncompetitive. Added in_band() and effective_demand(); effective_supply() gained the same hard band filter alongside its existing soft vwap-proximity filter (renamed that param mult to free up `band`). Wired into tools/scan.py stage 2 in place of the raw, unfiltered demand figure. Was flagged as an unimplemented refinement in saturation-design.md since the original design review. - tools/sell.py: self-contained tranche split (aggressive tranche capped at a volume quantile, median normally or 80th pct with --tight when a payment is imminent and stockout risk outweighs margin; patient tranche priced under the next competitor tier). Instant-bid comparison moved behind --show-bid (off by default). - Docs and roadmap updated accordingly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
63 lines
3.3 KiB
Python
63 lines
3.3 KiB
Python
"""puga.network.combine(): the transfer/freight logic, with fake simulate() results (no network calls)."""
|
|
import pytest
|
|
from puga import network
|
|
|
|
|
|
def fake_results(monkeypatch, per_base):
|
|
"""per_base: {name: flows dict} -> patches simulate() to return {"flows": ..., "profit": sum handled by caller}."""
|
|
def fake_simulate(plan, recipes, buildings, resources, fertility, price, faction=None, permits=(1, 2), built=None):
|
|
return {"flows": per_base[plan["_name"]], "profit": per_base[plan["_name"]].pop("_profit")}
|
|
monkeypatch.setattr(network, "simulate", fake_simulate)
|
|
|
|
|
|
def node(name):
|
|
return network.BaseNode(name, {"_name": name}, [], [], [], 0.0, lambda t, side="both": 100.0)
|
|
|
|
|
|
def test_transfer_fully_matched_only_charges_freight(monkeypatch):
|
|
fake_results(monkeypatch, {
|
|
"a": {"LST": {"out": 20.0, "inp": 0.0}, "_profit": 1000.0},
|
|
"b": {"LST": {"out": 0.0, "inp": 20.0}, "_profit": 500.0},
|
|
})
|
|
monkeypatch.setattr(network.fio, "materials", lambda: [{"Ticker": "LST", "Weight": 2.73, "Volume": 1.0}])
|
|
r = network.combine({"a": node("a"), "b": node("b")}, [network.Transfer("LST", "a", "b", trip_cost=1000, cargo=500)])
|
|
t = r["ledger"][0]
|
|
assert t["moved"] == 20.0 and t["shortfall"] == 0 and t["surplus"] == 0
|
|
assert r["total_profit"] == pytest.approx(1000 + 500 - t["freight"])
|
|
|
|
|
|
def test_transfer_shortfall_is_flagged_not_double_charged(monkeypatch):
|
|
fake_results(monkeypatch, {
|
|
"a": {"LST": {"out": 5.0, "inp": 0.0}, "_profit": 1000.0},
|
|
"b": {"LST": {"out": 0.0, "inp": 20.0}, "_profit": 500.0}, # needs 20, source only makes 5
|
|
})
|
|
monkeypatch.setattr(network.fio, "materials", lambda: [{"Ticker": "LST", "Weight": 2.73, "Volume": 1.0}])
|
|
r = network.combine({"a": node("a"), "b": node("b")}, [network.Transfer("LST", "a", "b", trip_cost=1000, cargo=500)])
|
|
t = r["ledger"][0]
|
|
assert t["moved"] == 5.0 and t["shortfall"] == 15.0 and t["surplus"] == 0
|
|
# b's own 'profit' already priced the missing 15 units at market (simulate()'s job) - combine() must not touch that
|
|
|
|
|
|
def test_transfer_surplus_is_flagged_and_sold_by_source(monkeypatch):
|
|
fake_results(monkeypatch, {
|
|
"a": {"LST": {"out": 40.0, "inp": 0.0}, "_profit": 1000.0},
|
|
"b": {"LST": {"out": 0.0, "inp": 9.0}, "_profit": 500.0},
|
|
})
|
|
monkeypatch.setattr(network.fio, "materials", lambda: [{"Ticker": "LST", "Weight": 2.73, "Volume": 1.0}])
|
|
r = network.combine({"a": node("a"), "b": node("b")}, [network.Transfer("LST", "a", "b", trip_cost=1000, cargo=500)])
|
|
t = r["ledger"][0]
|
|
assert t["moved"] == 9.0 and t["surplus"] == 31.0 and t["shortfall"] == 0
|
|
|
|
|
|
def test_freight_scales_with_weight_and_cargo_cap(monkeypatch):
|
|
fake_results(monkeypatch, {
|
|
"a": {"LST": {"out": 100.0, "inp": 0.0}, "_profit": 0.0},
|
|
"b": {"LST": {"out": 0.0, "inp": 100.0}, "_profit": 0.0},
|
|
})
|
|
monkeypatch.setattr(network.fio, "materials", lambda: [{"Ticker": "LST", "Weight": 2.73, "Volume": 1.0}])
|
|
r = network.combine({"a": node("a"), "b": node("b")}, [network.Transfer("LST", "a", "b", trip_cost=1000, cargo=100)])
|
|
t = r["ledger"][0]
|
|
assert t["weight"] == pytest.approx(273.0)
|
|
assert t["trips"] == pytest.approx(2.73) # 273 t / 100 t cargo cap
|
|
assert t["freight"] == pytest.approx(2730.0)
|