---
title: Fix contract-ledger lookups that pick the wrong prior transaction in league 1
type: task
status: draft
description: >-
  Trade copy-forward, activation and player-transaction readers in league 1 select the prior
  player_salary row by league-wide max(transaction_id) or an untiebroken occurred_at, so a contract
  can be copied from the wrong row. Measure the damage, define one current-contract rule, and fix
  all three readers.
base_uri: user:task/league/fix-league-contract-ledger-prior-row-lookups.md
created_at: '2026-10-07T15:48:04.450Z'
entity_id: e356fe5d-3577-429c-a370-33a5225e6a88
owner_identity_uri: █████████████████████████
priority: Medium
public_read: true
relations:
  - relates [[██████████████████████████-██-██████-███████-███-████████-██████████]]
tags:
  - user:tag/league-xo-football.md
  - user:tag/software-task.md
updated_at: '2026-10-07T15:48:04.451Z'
visibility_analyzed_at: '2026-11-05T23:49:24.972Z'
---

# Fix contract-ledger lookups that pick the wrong prior transaction in league 1

## Context

- Found while planning [[██████████████████████████-██-██████-███████-███-████████-██████████]]. League 1 uses `transactions.player_salary` as a contract ledger: acquisitions set it and every later move copies the prior row's value forward. Three readers pick that prior row wrongly.
- **Trade copy-forward** (`api/routes/leagues/trade.mjs:915,929`): `transaction_history` selects the latest row per player league-wide by `max(transaction_id)`, not the row for the team that holds the player, and not by `occurred_at`.
- **Activation ordering** (`libs-server/submit-activate.mjs:76`): the copied `player_salary` comes from a row ordered by `occurred_at` with no tiebreak, so two rows at the same instant resolve arbitrarily.
- **Player transactions** (`libs-server/get-player-transactions.mjs`): takes the newest row of any type league-wide by `max(occurred_at)`, so a release (salary 0) or another team's row can be returned as the current contract.

## Open questions

- Measure how many league 1 rows each defect has actually mis-copied before choosing between a code-only fix and a code fix plus a data repair.
- Decide the canonical "current contract row" rule once (team-scoped, `occurred_at` then `transaction_id`), and share it across all three readers.
