---
title: Resolve league-scoped client state from the league in view
type: task
status: completed
description: >-
  Three client sites still read an arbitrary league (and one an arbitrary team) from the
  AUTH_FULFILLED payload instead of the route league, repeating the invalid leagueId defect class
  fixed in cfeafe16e.
base_uri: user:task/league/resolve-league-scoped-state-from-league-in-view.md
created_at: '2026-09-02T15:13:24.178Z'
entity_id: 2bd3aed0-a6d2-4784-8563-f427e9923377
finished_at: '2026-09-08T02:42:04.163Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
public_read: true
started_at: '2026-09-02T17:25:11.394Z'
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-09-08T03:05:21.890Z'
visibility_analyzed_at: '2026-11-05T23:50:12.422Z'
---

Three surviving sites read an ARBITRARY league (and in one case an arbitrary team) out of the `AUTH_FULFILLED` payload instead of the league the route names. All three are the same defect class as the `invalid leagueId` bug fixed in `cfeafe16e` and deployed 2026-09-02, found by enumerating the class from the code rather than from the first symptom.

`GET /me` returns `leagues` and `teams` as two independent queries. Even now that both are ordered (`api/routes/me.mjs`), `leagues[0]` is the user's lowest-numbered league, not the one on screen — so for any manager in more than one league these read the wrong league's data.

## Sites

- **`app/core/players/sagas.js:182`** — the worst, and an exact repeat of the fixed bug: it takes `teams[0].team_id` and `leagues[0].league_id` from the same payload and passes them together to `load_team_players`. For user 1 that is team 1 with league 1 or, once the route differs, a mismatched pair that `verify-user-team` rejects with `invalid leagueId`. The surrounding code already has the resolved `app` and `league` in scope (lines 188-190), so the fix is to use `app.teamId` and `league.league_id`.
- **`app/core/auction/reducer.js:266`** — sets `lineupBudget` from `leagues[0].salary_cap * 0.9`. On the auction page, for a manager in more than one league, this is another league's salary cap. Time-sensitive: league 1's auction opens 2026-09-03T03:59:59Z.
- **`app/core/players/reducer.js:72`** — derives the position filter list from `leagues[0]`, so the player-filter positions can come from a league the user is not looking at.

## Shape of the fix

Same as `cfeafe16e`: resolve from the league in view. The reducer cases run on `AUTH_FULFILLED`, which does not know the route league directly, so each site needs either the already-resolved `app.leagueId` (available in the sagas) or a move to a payload that is league-scoped (`GET_LEAGUES_FULFILLED` / `GET_TEAMS_FULFILLED`), matching how `app_reducer` now splits the work between `AUTH_FULFILLED` and `GET_TEAMS_FULFILLED`.

## Verification

`test/app.team-resolution.spec.mjs` is the pattern to follow: parameterize over both league orderings so the fixture cannot hide an ordering-dependent bug, and confirm the pre-fix code fails the new cases before trusting them. Read `docs/guides/auction.md` before touching the auction reducer.

## Plan

- [x] Fix `app/core/players/sagas.js` to use the resolved `app.teamId` and `league.league_id` already in scope, rather than the positional payload reads
- [x] `app/core/auction/reducer.js` — the `AUTH_FULFILLED` case is DELETED rather than re-plumbed. `lineupBudget` has no reader anywhere in the repo, so there was nothing to resolve correctly
- [x] Fix `app/core/players/reducer.js` so the position filter list comes from the league in view — the seed moved to `players/sagas.js` `init`, which reads `get_positions_for_current_league`
- [x] Add `test/app.league-scoped-state-resolution.spec.mjs`: a source scan holding the whole class across `app/core`, plus the auction reducer parameterized over both league orderings
- [x] Confirm the pre-fix code fails every new case — the scan named all four positional reads, and the auction case produced 180 or 900 from one payload depending purely on league order
- [x] `yarn test:isolated` on every `test/app.*` spec (100 passing), `yarn lint` (0 errors), `npx prettier --check` on the changed files
- [x] Commit `cefaa3f62` with explicit pathspecs
- [x] Push — ████████ pushed `cefaa3f62`; it is on `origin/master`, which now heads at `e31ef97e6`
- [x] Deploy. Resolved without deploying: the auction-lane's own frontend deploy already carried this fix to `7f297e00b` (bundle built 2026-09-08 01:46Z), so no deploy was run here
- [x] Verify against the deployed bundle across all `*.js`, paired with a negative control — the deployed `dist` at `7f297e00b` has `data.teams[0]` and `leagues[0].salary_cap` at zero across all 81 files, with the `data.leagues[0]` control matching in `main.a162911e.js`
