Parent
#1
What to build
Extract Lot Merge logic out of the merge modal into a new pure module exposing mergeOpenLots(trades, asset) → trades'. The function encapsulates: synthesising the merged Lot's costBasis (size-weighted) and size, picking the earliest lot-opener as the kept Trade, removing the other lot-openers, and clearing lotNum on the asset's CALL Trades so they reattach to the surviving Lot. Audit-trail behaviour is unchanged — no synthetic MERGE Trade type.
The merge modal becomes view + confirmation only. It computes the preview using mergeOpenLots against the current Trades (or equivalent inspection helpers) and, on confirm, applies the same function via the project's current Trade write convention (save() + render()). A later slice will migrate the modal to the commitTrades seam.
Tests cover Lot Merge invariants using the test harness introduced in #2.
Acceptance criteria
Blocked by
Parent
#1
What to build
Extract Lot Merge logic out of the merge modal into a new pure module exposing
mergeOpenLots(trades, asset) → trades'. The function encapsulates: synthesising the merged Lot'scostBasis(size-weighted) andsize, picking the earliest lot-opener as the kept Trade, removing the other lot-openers, and clearinglotNumon the asset's CALL Trades so they reattach to the surviving Lot. Audit-trail behaviour is unchanged — no syntheticMERGETrade type.The merge modal becomes view + confirmation only. It computes the preview using
mergeOpenLotsagainst the current Trades (or equivalent inspection helpers) and, on confirm, applies the same function via the project's current Trade write convention (save() + render()). A later slice will migrate the modal to thecommitTradesseam.Tests cover Lot Merge invariants using the test harness introduced in #2.
Acceptance criteria
mergeOpenLots(trades, asset) → trades'src/js/places it after the Lot EnginemergeOpenLots(or its derived totals) — no inline merge arithmetic in the modalmergeOpenLotsand persists the result via the current Trade write conventioncostBasisand summedlotPremiums; CALLlotNumreferences on the asset are cleared; non-target assets are untouched; merging fewer than two open Lots is a no-opnode --test test/passespython3 build.py --checkpassesBlocked by