Skip to content

ESI: read the ship's cargo instead of the ISK wallet on the Abyss page #38

Open
6 of 6 issues completed

Description

@Fazorath

Problem Statement

The Abyss page works out an abyssal run profit from the change in the wallet. I don't sell loot after each run. I hold it for about a month and sell it all at once, so the wallet barely moves during a session and every run shows a profit of about 0. The wallet autofill from #19 fills in the wrong number. #41's "Loot (unsold)" was a workaround: it values the net change across every asset the character owns, so it also picks up market orders, contracts and purchases. It is per session, not per run, and ESI only refreshes it hourly. Neither number tells me what a single run made.

Solution

A run's profit becomes the change in cargo value: what is in the active ship's cargo hold when I leave the abyss (cargo after), minus what was in it when I went in (cargo before). I type both values from EVE's inventory estimated value. A "Fetch from EVE" button next to each field fills it from ESI and stamps when ESI read it. Cargo before is prefilled from the previous run's cargo after, and I can change it if I restocked or unloaded in station. Filaments and ammo used up during the run come out of the profit on their own, because they leave the hold.

The wallet no longer takes part in abyssal runs. The wallet fields come out of the Abyss page. The Wallet stat stays as a read-only figure from ESI. "Loot (unsold)" and the hourly asset poller behind it are removed. Old wallet-based runs keep the profit they were logged with. The Incursion page doesn't change.

See CONTEXT.md for the glossary and docs/adr/0001-run-profit-from-cargo-not-wallet.md for the decision record.

User Stories

  1. As an abyssal runner, I want a run's profit to be the change in my cargo value, so that loot I haven't sold yet still counts as profit for the run that brought it back.
  2. As an abyssal runner, I want filaments and ammo used up in a run to lower that run's profit, so that profit is net of what I spent to run it.
  3. As an abyssal runner, I want to enter the cargo before and cargo after for each run, so that each run's profit stands on its own.
  4. As an abyssal runner, I want cargo before to be prefilled from the previous run's cargo after, so that I don't retype it when I haven't touched the hold.
  5. As an abyssal runner, I want to change the prefilled cargo before, so that I can account for restocking or unloading the hold in station between runs.
  6. As an abyssal runner, I want the first run of a session to start with cargo before empty, so that I enter what I actually took in.
  7. As an abyssal runner, I want a "Fetch from EVE" button next to cargo before, so that I can fill it from ESI instead of typing it.
  8. As an abyssal runner, I want a "Fetch from EVE" button next to cargo after, so that I can fill it from ESI instead of typing it.
  9. As an abyssal runner, I want each fetch to say "From EVE at HH:MM", using the time ESI read the assets, so that I can tell when the value is stale (ESI caches assets for up to an hour).
  10. As an abyssal runner, I want a fetched value to stay editable, so that I can overwrite a stale reading with EVE's inventory estimated value.
  11. As an abyssal runner, I want the fetch to value only the active ship's cargo hold, so that my hangars, drone bay, loaded ammo and other ships don't count.
  12. As an abyssal runner, I want the fetch to use whichever ship EVE says I'm flying when I press the button, so that switching ships between runs just works.
  13. As an abyssal runner, I want ammo kept in the cargo hold to count as cargo, so that I don't have to separate it out.
  14. As an abyssal runner, I want cargo items with no market price (for example abyssal modules) left out of the fetched value and shown as a count ("· 2 unpriced"), so that I know the figure is incomplete and can add them myself.
  15. As an abyssal runner, I want a clear message when a fetch fails (signed out, ESI error, rate limit), so that I know to type the value instead.
  16. As an abyssal runner, I want to log a run from cargo after and the timer alone, with cargo before already filled in, so that logging stays as fast as it is now.
  17. As an abyssal runner, I want the pocket overlay's one field to be cargo after, so that I can log from the overlay without opening the full window.
  18. As an abyssal runner, I want the "left the abyss" prompt from run detection to tell me to enter my cargo after, so that the prompt matches the form.
  19. As an abyssal runner, I want to start a session by picking only the filament, so that I'm not asked for a wallet that no longer matters.
  20. As an abyssal runner, I want to edit a logged cargo run's cargo before, cargo after and time left, so that I can fix a typo.
  21. As an abyssal runner, I want editing or deleting a run to leave every other run's profit alone, so that one correction doesn't quietly change other runs.
  22. As an abyssal runner, I want an old wallet-based run to be edited as profit and minutes, so that I can still correct runs logged before this change.
  23. As an abyssal runner, I want old wallet-based runs to keep the profit they were logged with, so that my history and lifetime totals don't change.
  24. As an abyssal runner with a session left open across the update, I want that session to carry on with cargo runs, with its first cargo before empty, so that I don't have to end it or migrate anything.
  25. As an abyssal runner, I want the Session stat, ISK/hr, average per run, history, chart and weather rates to use cargo-based run profit, so that every figure agrees.
  26. As an abyssal runner, I want a read-only Wallet stat on the Abyss page, read from ESI, so that I can still see my balance for reference.
  27. As an abyssal runner, I want the Wallet stat to show "—" with a hint when I'm signed out, so that its absence is explained.
  28. As an abyssal runner, I want "Loot (unsold)" gone from the Abyss page and the session-end summary, so that there is one profit figure, not two that disagree.
  29. As an abyssal runner, I want the app to stop polling my assets every five minutes, so that it doesn't make ESI calls I no longer need.
  30. As an abyssal runner, I want the CSV export to include cargo before and cargo after for each run, so that my exported data shows how each profit was worked out.
  31. As an abyssal runner, I want the CSV export to keep the wallet-after column (empty for cargo runs), so that old exports and spreadsheets built on them still line up.
  32. As an abyssal runner, I want restoring a backup made before this change to work, so that old backups stay usable.
  33. As a CLI user, I want the terminal tracker to ask for cargo before and cargo after instead of the wallet, so that the CLI and the desktop app work out profit the same way.
  34. As an incursion runner, I want the Incursion page to keep reading payouts from the wallet journal, so that incursion tracking is unaffected (payouts arrive as ISK).
  35. As a signed-out user, I want the cargo fields to work fully by hand, so that ESI is a convenience and never a requirement.

Implementation Decisions

Domain and storage (the Tracker)

  • A run gains two nullable fields: cargo before and cargo after, in millions of ISK like every other amount. A cargo run has both set and no wallet-after. An old wallet run has wallet-after set and no cargo values. That is how the two kinds are told apart.
  • The schema migration only adds the two columns to the runs table, the same way earlier columns were added to sessions. No data is migrated or recomputed (ADR 0001).
  • Logging an abyssal run takes cargo before, cargo after and time left. Profit = cargo after − cargo before. Minutes = 20 − time left. Both cargo values must be finite and time left must be valid, using the existing validators. A negative profit is allowed, for example after losing cargo.
  • A lookup returns the cargo after of the session's latest cargo run, or nothing if there is none (a new session, or one with only wallet runs). The UI and CLI use it to prefill cargo before.
  • Editing a cargo run changes its cargo before, cargo after and time left, and recomputes only that run's profit and minutes.
  • Editing an old wallet run takes profit and minutes directly and changes no other run. The wallet re-chaining on edit is removed.
  • Deleting any abyssal run no longer re-bases the next run. This follows "editing or deleting a run never re-bases another". The helper that finds the next run in the chain goes away.
  • A session's starting wallet stays in the schema for old sessions. New abyss sessions are started without one.
  • "Current wallet from the run log" is removed, since nothing in the run log tracks the wallet any more.
  • Loot (unsold) is removed: the baseline and valuation methods, the Baseline and Loot records, and creating the loot table on new databases. An existing loot table in an old database is left as it is (no migration).
  • CSV export adds cargo_before_millions and cargo_after_millions columns and keeps isk_after_millions (empty for cargo runs). Backup and restore are otherwise unchanged. Restoring an older database goes through the same migration.

ESI

  • A new cargo reader takes a signed-in client and returns a cargo valuation: value in millions, the number of unpriced item types, and when ESI last answered for the asset list.
  • It reads the active ship from the character's ship endpoint (the esi-location.read_ship_type.v1 scope is already requested) to get ship_item_id. From the paged asset list it keeps the items whose location_id is that ship and whose location_flag is Cargo. It values them with the existing market prices reader (CCP's average price, or the adjusted price when there is no average).
  • Blueprint copies are left out, as in the current asset reader.
  • Unpriced items are left out of the value and counted by item type, as the current loot valuation does.
  • The existing asset reader and price reader are reused or reshaped. The cargo reader needs each entry's location and flag, which the current reader throws away when it totals quantities by type. The all-assets change valuation is removed with Loot (unsold).
  • Malformed ESI responses raise ValueError, the same as the existing readers.

Abyss page (desktop)

  • Start form: the wallet field and its Fetch button are removed, leaving the filament tier and weather.
  • Log form: "Cargo before (M)" and "Cargo after (M)" fields, each with its own "Fetch from EVE" button and status note, plus "Time left (min)" (blank = timer), as now.
  • After a run is logged, cargo before is set to the cargo after just logged, and cargo after and time left are cleared. When a session starts or resumes, cargo before is prefilled from the session's latest cargo run, or left empty.
  • A successful fetch fills its field to two decimals. The note reads "From EVE at HH:MM" (using ESI's fetched-at time) and adds " · N unpriced" when N > 0. It also says ESI can lag up to an hour and the value can be edited. Errors appear in the note in the critical colour, as the wallet fetch does now.
  • The pocket overlay's single field becomes cargo after, and its label changes to match. Cargo before comes from the full form's prefilled value.
  • The run-detection "left the abyss" prompt tells the user to enter cargo after and moves focus to that field.
  • Stats: Session, ISK/hr, Time, and Wallet. The Wallet stat is read-only, read from ESI (using the existing wallet reader) when a session starts or resumes and after each logged run. Its sub-line is "from EVE at HH:MM". When signed out it shows "—" with a hint. The Loot (unsold) stat, the five-minute asset poller and the loot line in the session-end summary are removed.
  • Edit dialog: a cargo run shows Cargo before (M), Cargo after (M) and Time left (min). An old wallet run shows Profit (M) and Minutes.
  • The page subtitle and the Settings sign-in copy are reworded so they no longer talk about entering the wallet for abyssal runs.

CLI

  • The terminal Abyss tracker asks for the filament, then for each run asks cargo before (defaulting to the previous run's cargo after), cargo after and time left. The per-run summary shows cargo after instead of "New total".

Unchanged

  • The Incursion page, the wallet-journal payout logging and incursion site editing.

Testing Decisions

  • Tests check behaviour through the public interfaces only: what a run records, what the page shows and what gets exported, not internal helpers or the SQL. Three seams, all already in use:
    1. Tracker on a temporary database: logging cargo runs (profit and minutes), validation, the latest-cargo-after lookup, editing cargo runs and old wallet runs without touching other runs, deleting without re-basing, mixed sessions (wallet runs and cargo runs in one session) totalling correctly, a database from before the new columns opening and gaining them, and the CSV columns. Prior art: test_core.py (the run, edit and migration tests) and test_export.py (CSV and restore from an older schema).
    2. The cargo reader against a fake ESI client serving canned ship, asset and price bodies: only items in the active ship's Cargo flag count (not other flags in the same ship, not other ships, not hangars), paging, blueprint copies left out, unpriced items counted, the fetched-at time passed through, and malformed bodies rejected. Prior art: test_loot.py (the FakeClient and item builder) and test_wallet.py.
    3. The Abyss page driven through gui.App with the account mocked: logging a run from typed cargo values, cargo before prefilled after a run and on resume, Fetch from EVE filling a field with its stamp and unpriced count (cargo reader mocked), the Wallet stat read-only from a mocked wallet reader and "—" when signed out, the edit dialog fields for both kinds of run, and the pocket overlay logging from cargo after. Prior art: test_loot_page.py (replaced by these tests) and test_pocket.py (its wallet-based tests move to cargo).
  • Existing wallet-chaining tests (test_abyss_runs_chain_wallets, the delete and edit re-base tests, the loot baseline and valuation tests) are rewritten or removed to match the new behaviour, not kept passing against the old one.
  • Tk-based tests keep the existing skip when no display is available.

Out of Scope

  • Drones, the drone bay, loaded ammo, fitted modules and the ship hull. The user accounts for those themselves.
  • Items inside containers in the cargo hold (their location is the container, not the ship). Only items directly in the hold count.
  • Fetching cargo automatically on entering or leaving the abyss. Fetch is a button, because ESI's asset cache is usually stale right after a run.
  • Pricing unpriced items (abyssal modules, for example) through a third-party appraisal service, or choosing Jita buy/sell over CCP's average price.
  • Recomputing or migrating old wallet-based runs or sessions.
  • Any change to the Incursion page or to incursion profit.
  • Valuing all assets or tracking net worth.

Further Notes

  • Grilled and settled on 2026-10-25. Decisions are recorded in CONTEXT.md (glossary: Run, Session, Active ship, Cargo, Cargo value, Run profit, Cargo before / Cargo after, Unpriced item, Wallet) and ADR 0001. Both files are in the working tree but not committed yet, so the first ticket should commit them.
  • Overlaps with ESI: fill in the wallet balance automatically #19 (the wallet autofill this replaces for the Abyss page) and Value unsold loot with market prices #41 (Loot (unsold), removed here; its pricing code is reused).
  • ESI location_flag for the cargo hold is Cargo. The issue's original to-do item "confirm against real data" stands: check this against a real character's asset list before or during implementation.

Activity

  1. self-assigned this
    on Oct 25, 2026
  2. Fazorath commented on Oct 25, 2026

    @Fazorath
    OwnerAuthor

    Triage against #41: that PR priced the net change across all of the character's assets since session start and shows it as Loot (unsold) with a "from EVE at" stamp. It does not read the active ship's cargo hold and does not touch the wallet autofill, so those two items stay open. Kept in In Progress and assigned.

  3. Fazorath commented on Oct 25, 2026

    @Fazorath
    OwnerAuthor

    Original issue body, kept here before the spec replaced it:


    The wallet autofill (#19) fills in the character's ISK balance. What was wanted for the Abyss page is the value of what is in the ship's cargo hold (the loot picked up during a run), not the ISK wallet.

    To do

    • Decide what the field should hold: cargo contents priced in ISK, or a plain item list. Settled in Value unsold loot with market prices #41 as a priced ISK value ("Loot (unsold)")
    • Read the active ship's cargo from ESI. Assets (esi-assets.read_assets.v1, already requested) list items by location, so cargo should be the items located in the ship. Confirm this against real data. Value unsold loot with market prices #41 values the net change across all assets, not the hold
    • Show it on the Abyss page next to the wallet fill, with a last-updated stamp. Done for the all-assets loot value in Value unsold loot with market prices #41; the cargo-only value still needs showing
    • Settle how the ISK wallet autofill stays: keep, move or remove

    Overlaps with #21 (merged in #41): the pricing and the Loot stat live there. What is left is reading the ship's cargo and deciding the wallet autofill.

  4. added
    ready-for-agentSpec'd and safe for the night shift to build
    and removed
    needs-grillNeeds a grill session before it can be specced
    on Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

esiEVE Online ESI integrationready-for-agentSpec'd and safe for the night shift to build

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions