---
title: Fix the misaddressed reply on the auction award cap refusal
type: task
status: completed
description: >-
  The award-time cap refusal in _validate_team_can_acquire_player replies to the cached top
  transaction rather than to the bid it was handed, so on the stale-cache path that is the only way
  to reach that branch, the wrong manager is notified.
base_uri: user:task/league/fix-auction-award-cap-refusal-reply-address.md
created_at: '2026-09-02T17:17:14.755Z'
entity_id: 52eb380d-9d86-42cb-9f84-30147d780971
finished_at: '2026-09-07T23:04:28.465Z'
observations:
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: Low
public_read: true
relations:
  - relates [[████████████████████-███████-███████████-██████████-████████]]
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-09-07T23:04:28.465Z'
visibility_analyzed_at: '2026-11-05T23:49:17.644Z'
---

`_validate_team_can_acquire_player` in `api/sockets/auction.mjs` has two refusal branches two lines apart, and they address their replies differently:

- roster space replies to `bid.user_id` — the bid the method was handed
- cap replies to `this._transactions[0].user_id` — the socket's in-memory transaction cache

The `bid` is in scope on both. The cache read is an oversight, not a design, and the fix is one expression.

## Why it is not merely cosmetic

The cap branch is the one branch that is UNREACHABLE unless the cache is stale. `_validate_bid` enforces the same bound against `_teams` at bid time, so on a cache agreeing with the database the award check can never disagree. It comes alive only when a trade or a commissioner-override release moves a team's real cap during a live block — exactly the case `nominate()` documents, and the case `test/auction.eligibility-validation.spec.mjs` reproduces.

So the branch that fires only on a stale cache reads its recipient FROM that stale cache. Where the two diverge, the wrong manager is told "exceeds salary limit" and the manager whose bid was actually refused is told nothing — their player simply never appears.

## The change

In `_validate_team_can_acquire_player`, the cap branch reply becomes `this.reply(bid.user_id, 'exceeds salary limit')`, matching the roster-space branch above it.

## Test

`test/auction.eligibility-validation.spec.mjs` already pins the shipped behaviour as a full `{ user_id, error }` object, deliberately, so that a fix cannot land silently. Its spec "refuses to award a player the team can no longer afford" will go red on this change and its expectation moves with the fix.

A second spec is needed for the fix to be worth making: one where the top cached transaction and the winning bid belong to DIFFERENT users, which is the only condition under which the two addresses differ at all. The existing spec cannot show the fix works, because on its path both resolve to the same manager. Prove it red against the unfixed source before accepting it.

## Blocked until

League 1's auction has opened and closed. This is auction runtime and the auction was armed when the defect was found.
