---
title: Resolve the percentile field requests player-fields.js cannot serve
type: task
status: completed
description: >-
  The 44-unserved figure was measured against the wrong source: those requests are served by the
  browser worker, not the percentiles table. One real defect, a dryprecy/drprecy typo blanking a
  default column, is fixed, gated and deployed.
base_uri: user:task/league/decide-unserved-percentile-field-requests.md
created_at: '2026-09-02T15:31:51.992Z'
entity_id: 5807f838-0d1e-47de-958a-97957cc82d5b
finished_at: '2026-09-02T18:00:55.103Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: Medium
public_read: true
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-11-06T02:28:01.924Z'
visibility_analyzed_at: '2026-11-05T23:49:06.309Z'
---

## Outcome

There was no partition to decide. The premise that opened this task was measured against the wrong source, and only one of the 44 names was actually broken.

Shipped in league `7e86f6138`, deployed to both hosts and the frontend bundle on 2026-09-02:

- `stats.dryprecy` renamed to `stats.drprecy` in `app/core/player-fields.js` and `app/core/players/default-players-views.js`.
- `test/app.percentile-field-consumer-resolution.spec.mjs` added, grading each request against the source that serves it.
- `percentile_field_vocabulary` in `scripts/generate-nfl-team-seasonlogs.mjs` corrected to include `points`.
- The withdrawn figure corrected in `percentile-field-resolution`'s calibration prose in `db/checks/registry.mjs`.

## Why the premise was wrong

`app/core/player-fields.js` has TWO percentile families, and the inherited measurement graded one of them against the other's source.

The WORKER family — 55 distinct fields, every one of the 44 among them — pins `percentile_key: 'PLAYER_PLAY_BY_PLAY_STATS'`. Nothing stores those. `app/core/stats/sagas.js` runs `workerCalculateStatsFromPlays`, whose `calculatePercentiles` call takes its vocabulary from `extended_player_stats` in `libs-shared/constants/stats-constants.mjs`, and `app/core/percentiles/reducer.js` writes the result into state under that key. The `percentiles` table holds ZERO rows under it and always has, by design.

The STORED family — 40 distinct fields — reaches its key through `opponent_field()` or its own `get_percentile_key`, resolving to `${pos}_AGAINST_ADJ` at render. Those come from `scripts/generate-nfl-team-seasonlogs.mjs`. All 40 resolve against production.

Graded correctly, 43 of the 44 are in `extended_player_stats` and are produced by `libs-shared/calculate-stats-from-plays.mjs` (`pts` is set by the worker itself). The lone exception, `dryprecy`, was a misspelling of the writer's `drprecy` — wrong in the entry name, `player_value_path` and `percentile_field` alike, so the whole Dropped Receiving Yards column rendered blank, in a default view, rather than only losing its shading.

## The gate

`percentile-field-resolution` grades values that EXIST in `percentiles` and is structurally blind to a request nobody wrote a row for. The new spec asks the mirror question over the consumer, and splits the file by family to do it honestly — grading either family against the other's vocabulary is confidently wrong in both directions, which is exactly how the 44 figure arose.

Four assertions, four negative controls, each control failing only the assertion that tests its changed behavior, each mutation asserted applied before its run.
