deriveOrderOutcome is obviated by #950; the strong primitives are computeOrderPnl + classifyQuarterLineOutcome
Status: ACCEPTED (Bhargav + Architect, 2026-07-09). Supersedes the "re-apply deriveOrderOutcome" item of the merge plan / ADR-0007's extraction.
The two settlement paths (grounded, 953)
Settlement outcome is derived on two structurally different paths with different inputs — and a deliberately different zero-boundary rule:
- Per-order, provider-reported —
releaseMarketCredit(settlement.ts:2240) / the BetsApi+cleared path. Input: a per-order provider result + the order's own pnl. Rule:pnl.isZero() → void,>0 → win, elselose. A per-order zero pnl means the provider refunded → void. - Market-wide netting —
settleMarketForUser(settlement.ts:820). Input: the netted exposure contribution vector atwinnerIdx, NOT a provider result. Rule:pnl.gte(0) → win. A netted zero contribution at the winning index means the bet was on the winner and broke even → win (and is therefore included in commission), NOT a refund.
Our deriveOrderOutcome (#951) is a WRAPPER for path 1 only — its own docstring states
"settleMarketForUser … deliberately does NOT route through this function." Both paths already build on
the same pure math: computeOrderPnl and classifyQuarterLineOutcome (settlement.ts:230/304).
Verdict
- The strong, architecturally-correct functions that MUST remain =
computeOrderPnl+classifyQuarterLineOutcome. They are the single source of settlement math; #950 kept them and both paths use them. Neither PR rewrites them. deriveOrderOutcomeis NOT superior to #950's structure. It was valuable on dev1 where the per-order path had messy inline outcome logic. #950's rewrite already achieved clean settlement: math primitives shared, each path's outcome logic expressed where it belongs.deriveOrderOutcome's one extra (bundling the quarter-line refinement into path 1) is still available by callingclassifyQuarterLineOutcomedirectly. It is therefore obviated on 953.- Do NOT unify the two paths under one outcome function. Forcing path 1's
isZero → voidonto the netting path would flip break-even winning orders fromwin→void. Void orders are excluded from commission (settlementOutcome === 'void'→continue, settlement.ts:1398), so this would under-charge commission on break-even wins — a real ledger change. That is the divergence ADR-0007 protects and the reason to leave the two rules distinct.
Consequence
- The #951 "settlement axis" delta does not re-apply to 953. Slices that DO apply: decline→declined
(done) + size columns (done). The only clean settlement remnant is dropping the dead
'push'value from the canonicalSettlementResulttype (prod-verified no rows; provider-inputpush→voidmapping stays) — a type cleanup, done separately. - Any future consolidation of the two outcome rules is a deliberate settlement decision owned by the settlement path (Pran) + financial-guardian, per ADR-0007 — never a mechanical re-apply.