---
title: Backfill league format projections and draft values for the 18 restored formats
type: task
status: completed
description: >-
  Closed as no work needed: measurement showed neither league_format_projections nor
  league_format_draft_values is a real gap for the 18 restored formats, because their peers do not
  carry those either.
base_uri: user:task/league/backfill-league-format-projections-and-draft-values.md
created_at: '2026-09-15T14:42:30.829Z'
entity_id: 23e1da9f-92f7-4b0e-8af6-c715d49f44c2
finished_at: '2026-09-15T16:35:03.994Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
public_read: true
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-09-15T16:35:11.600Z'
visibility_analyzed_at: '2026-11-06T00:17:40.757Z'
---

The gamelog backfill (`scratch/league/league-format-gamelog-backfill/`) ran with `--only-steps league_format_gamelogs,league_format_seasonlogs,league_format_careerlogs`, leaving `league_format_projections` and `league_format_draft_values` unrun for the 18 formats it restored.

**Measurement since then says neither is a gap** — see below. This task opened on the assumption they were outstanding work; that assumption did not survive checking what the 18 formats' peers hold.

## Why they were excluded rather than deferred by accident

`league_format_projections` is the step that hung on 2026-09-15, stalling a run for 7h47m. Signals 129928 and 129929 are about gamelog coverage, so putting the one known-bad code path on the critical path of a multi-hour job bought nothing and risked the whole run.

`league_format_draft_values` depends on `league_format_careerlogs`, which this run does produce, so it is unblocked the moment the gamelog job lands.

## What is already fixed

League `c350d98ab` sets `keepAlive` on the postgres connection. The 06:37Z hang was a lost response on a remote database socket with no keepalive, so the client waited forever for a packet that was never coming. With keepAlive the same event surfaces as a socket error, which `--continue-on-error` handles.

**That is a mitigation, not a diagnosis.** It makes the hang survivable; it does not establish that the tunnel was the only cause. Treat the projections step as unproven until it has run clean end to end.

## Measured 2026-09-15: neither step is actually a gap

The gamelog job landed clean (20 of 20, `verify-format-data-coverage` reports all 32 named formats free of regressions). Before running the excluded steps, the premise was checked against what the 18 formats' PEERS actually hold — and the premise does not survive.

**Historical projections are the exception, not the norm.** Only 4 of the 32 named formats carry any pre-2026 `league_format_player_projection_values` at all:

| format | pre-2026 rows |
| ------ | ------------- |
| `half_ppr_10_team_superflex` | 101,721 |
| `07db3422-c456-4402-9468-273a5d122514` | 79,955 |
| `f663e70c-8232-4881-8af6-8ca38379c068` | 60,754 |
| `genesis_10_team` | 18,720 |

Every other named format, including `half_ppr_10_team` — the reference format with complete 2001-2026 gamelog coverage — holds **2026 only**, at exactly the same 9,144 weekly rows the 18 already have. So the 18 are not missing projections relative to their peers. They match.

**`half_ppr_10_team_superflex` is on that list only by accident.** It is the format the 06:37Z run was processing when it hung, and it got a full 2020-2026 projection history written before stalling. Its per-year counts agree with the other history-carrying formats, so the data is consistent rather than half-written — but it is inconsistent with its own sibling `half_ppr_10_team`, which has none.

**Draft values track live leagues, not the catalog.** Seven formats carry `league_format_draft_pick_value`, and the set is mostly opaque UUID formats plus `draftkings_classic` and `genesis_10_team` — the formats real leagues are priced in. Both hosted leagues run `genesis`. Neither `half_ppr_10_team` nor `half_ppr_10_team_superflex` has draft values, so this is not something the 18 are missing either.

**What running the steps anyway would cost:** roughly 100k projection rows per format, about 1.8M rows across the 18, written to catalog formats with no identified consumer — using the one code path with a hang history.

## Plan

**Closed as no work needed.** The step was excluded from the backfill for a defensive reason (it hangs); the measurement above gave the better reason — there is nothing to backfill. The projection-history asymmetry is recorded rather than acted on.

1. ~~Is the catalog supposed to carry projection history at all?~~ Settled by the measurement: it is not the norm, so the 18 are not behind. If that ever changes, the gap is 28 formats rather than 18 and wants its own task.
2. ~~Leave `half_ppr_10_team_superflex`'s accidental history, or prune it?~~ **Left in place.** Pruning was the riskier option and buys only cosmetic consistency.
3. **Not run, and not needed** — projections for one format in the foreground. If a future ruling wants catalog-wide history, this is still the right way to start: one format, watched, because the step has a hang history. League `c350d98ab` added `keepAlive`, which makes the hang survivable but does not prove the tunnel was the only cause.
4. **If it ever hangs again**, capture the stack before killing it — `kill -SIGUSR1` on the node process, or attach with `node --inspect`. The one thing both previous post-mortems lacked was any view of where the client was parked.
5. ~~`league_format_draft_values`~~ — no action; revisit only if a league is ever priced in one of these formats.
6. ~~Verify with `scripts/verify-format-data-coverage.mjs`.~~ Done — all 32 named formats free of coverage regressions.
