---
title: Derive the Sleeper corpus scoring mapper from the mirror adapter
type: task
status: completed
description: >-
  The corpus rule-set mapper refuses or mis-maps Sleeper keys the stat-dict-fitted mirror adapter
  already scores (fum, pass_fd, the positional first-down bonuses, touchdown-is-not-a-first-down).
  Make the adapter's canonical mapping the one Sleeper vocabulary and project the corpus tuple from
  it.
base_uri: user:task/league/derive-the-sleeper-corpus-scoring-mapper-from-the-mirror-adapter.md
created_at: '2026-10-24T21:31:22.467Z'
entity_id: f7a9dc27-52e2-43e8-8924-21764247f793
finished_at: '2026-10-24T23:42:59.622Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: Medium
public_read: true
relations:
  - relates [[██████████████████████████-██████-█████-███████-██-██████-██████████]]
started_at: '2026-10-24T22:32:13.311Z'
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-10-24T23:57:13.171Z'
visibility_analyzed_at: '2026-11-06T00:17:50.111Z'
---

## Problem

Two mappers read Sleeper `scoring_settings` and they have drifted apart. The mirror adapter (`libs-server/external-fantasy-leagues/adapters/sleeper.mjs`, `map_scoring_settings_to_canonical`) has been fitted key by key against the vendor's stat dict and reproduces Sleeper's points on every 2026 mirror. The corpus mapper (`libs-server/external-league-corpus/platforms/sleeper/map-rule-set.mjs`, `map_sleeper_scoring_settings_to_scoring_format`) has not kept pace.

Measured 2026-10-24 by feeding single keys to both:

- **Claimed by the adapter, refused by the corpus mapper:** `fum`, `pass_fd`, `bonus_fd_qb`, `bonus_fd_rb` and `bonus_fd_wr`. On the 19:04Z resolver run these were the first refusal of 26,144, 3,546, 195, 242 and 24 leagues. Counts are first-hit, so they understate.
- **Wrong in the corpus mapper:** `bonus_fd_te` goes to receiving first downs only. It also never states `touchdown_is_first_down = false`. Over 2026 weeks 1-7, every `bonus_fd_*` equals `pass_fd + rush_fd + rec_fd` on all 1,316 player-weeks (QB 203, RB 352, WR 533, TE 228), so each bonus reaches all three first-down stats for its position.
- **Claimed by neither:** `kr_yd`, `pr_yd`, `pass_sack`, `pass_inc`, `pass_td_40p`, `pass_td_50p`, `rush_td_40p`, `rush_td_50p`, `rec_td_40p`, `rec_td_50p` and `bonus_rush_td_qb`. These are out of scope here, except that the shared mapper must keep refusing them by name.

Of the 106,654 corpus leagues, 19,143 set a nonzero base first-down rate, so aligning re-identifies every one of their rule sets.

## Target

There should be one Sleeper scoring vocabulary. The corpus mapper derives its tuple from the adapter's canonical mapping, the same way both already share `sleeper-bonus-rules.mjs`, rather than keeping a second key table.

- Extract the adapter's mapping into a pure function both import.
- The corpus mapper then does three things:
  - It refuses on any nonzero key the shared mapping leaves unclaimed and that is not in `OUT_OF_MODEL_SLEEPER_KEYS`.
  - It projects the result onto its rule-set columns, with an absent column as a hard 0.
  - It keeps its two-point disagreement refusal.
- Delete `SCORING_COLUMN_BY_SLEEPER_KEY` and `DERIVED_SOURCE_SLEEPER_KEYS` once nothing reads them.

## Plan

- [x] Extract the shared mapping and point the corpus mapper at it, in `sleeper-scoring-settings.mjs`.
  - Over 20,000 random dicts the adapter's output was byte-identical.
  - Ruled 2026-10-24: `touchdown_is_first_down` is stated false for every league, so the whole corpus re-identifies.
- [x] Resolve return touchdowns.
  - The player key `st_td` sets both return columns, with absent read as 0, so a D/ST key never pays a player.
  - `def_st_td` is claimed only when it pays the same rate in every column it reaches.
  - `pr_td`, `kr_td`, `def_pr_td` and `def_kr_td` are inert: claimed, with no column.
  - `st_*` keys report against individual players, not the D/ST.
- [x] Prove the corpus change on the corpus itself. Mapped all 106,654 Sleeper payloads both ways, and none is newly refused.
- [x] Review, merge and deploy. An independent review found the D/ST-key leak, fixed before merge. Merged as league `edd898b04` and deployed to both hosts at about 23:15Z.
- [x] Re-sync the 2026 mirrors and rerun process-matchups. All 16 Sleeper mirrors now pay return touchdowns at 6. 17 of 18 mirrors compare at 0 diverged, and lid 124 is skipped because it carries no vendor points.
- [x] Apply the migration and run the resolver. 48,507 pointers were cleared and 64,986 leagues re-resolved into 29,878 rule sets. The canary held 200 of 200 and the in-appetite count held at 65,755.
- [x] Fold `pass_inc` onto the attempt and completion rates (league `3323e4c92`, deployed). It equals `pass_att - pass_cmp` on 869 of 869 player-weeks, and 355 more leagues resolved.
- [x] Gate the divergence-control check on the 2026-10-27 and 10-28 finalize-week runs, which run on the second API host rather than `league`. The gate is `user:scheduled-command/after/after-ecdbc23d.md`, firing 2026-10-28T08:00Z. It raises `pipeline_failure` on any divergence, a stale allowlist entry, an open process-matchups signal, or fewer than 17 compared mirrors.

## Outcome

One Sleeper scoring vocabulary now serves both the mirrors and the corpus.

The remaining refusals need new engine stats rather than mappings:

| Keys | Leagues first-refused | Missing stat or rule |
|---|---|---|
| `rec_td_40p`, `rec_td_50p` and the pass and rush equivalents | about 18,200 | A big-play bonus rule on a touchdown's length |
| `kr_yd`, `pr_yd` | about 7,200 | Player return yards |
| `pass_sack` | about 4,100 | Sacks taken |
| `bonus_rush_td_qb` | 7 | A quarterback rushing-touchdown override |
