Add multi-base chain modelling, fix price-band-aware demand/supply, tranche-split sell tool

- 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>
This commit is contained in:
2026-09-25 14:32:09 +02:00
co-authored by Claude Sonnet 5
parent e2e592cae3
commit 58db08b921
15 changed files with 434 additions and 21 deletions
+21
View File
@@ -97,6 +97,27 @@ plan nets that against the smelters to ~0). This bit a first version of `tools/b
comparing it against the by-hand restock calc, not by a unit test (the pure functions were right,
the plan file chosen was wrong).
## Multi-base chains: `puga.network`
For a decision that spans two or more bases (mine LST at Nike, ship it, turn it into BSE at
Deimos), don't price the transferred material at market on both ends — that double counts a trade
that never happens. `puga.network.combine()` simulates each base independently (each base's own
`profit` is still correct market-priced), then nets any transferred material between a producer's
surplus and a consumer's need, charging only the real freight for what's actually moved; leftover
surplus is still validly sold at market by the source, leftover deficit still validly bought by the
destination — those are already right in each base's own numbers, so `combine()` only adds the one
correction neither side has. CLI: `tools/network.py <chain.yaml>`, spec format and a worked example
(Nike LST -> Deimos PP2/BSE) in `plans/chains/`.
Two gotchas specific to this: (1) each base's plan must be self-contained (see above) - Nike's plan
needs its OWN housing even though Deimos's doesn't compete for it; (2) a NEW base's plan always
prices a fresh core module unless the founding source (e.g. a Core Module Kit) actually covers it -
mark it with `cm_free: true` on that base in the chain spec (mirrors `tools/simulate.py --cm-free`),
or the phantom ~200k core-module cost craters an otherwise-fine ROI. (3) each base's reported
profit/day is for its WHOLE plan, not the marginal addition - for "is this new building worth it",
also simulate the base without the addition and diff, same as `tools/simulate.py`'s built-vs-planned
new_capex logic but applied to profit instead of capex.
## Conventions to keep
- Cache TTLs matter: market data is cached ~15 min, static game data ~24h (`puga/cache.py`).