---
title: Cover the quarter, down and win-probability derived columns in generate-player-snaps
type: task
status: completed
description: >-
  test/scripts.generate-player-snaps.spec.mjs asserts on no column derived from quarter, down_number
  or win_probability, and its fixture sets quarter and down_number identically, so a transposition
  of the two would leave it 4/4 green.
base_uri: user:task/league/cover-generate-player-snaps-derived-columns.md
created_at: '2026-08-06T16:32:14.242Z'
entity_id: f63dd709-a704-4332-a223-a204d3ccce53
finished_at: '2026-08-06T16:37:41.706Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: Medium
public_read: true
tags:
  - user:tag/league-xo-football.md
  - ███████████████-██████-███████████
  - user:tag/software-task.md
updated_at: '2026-08-06T16:37:58.475Z'
visibility_analyzed_at: '2026-11-05T23:48:40.964Z'
---

## Context

`test/scripts.generate-player-snaps.spec.mjs` was written 2026-08-05 (`e88f9650c`)
to cover a writer with a documented history of shipping broken — `generate-player-snaps`
named three nonexistent columns under a fully green suite, raising 42703 on every
run while `main()` caught the throw and exited 0. The spec executes the real
insert, which is the right shape and is why it caught that class.

An adversarial review on 2026-08-06 of the `nfl_plays` alias migration
(`20e4a31f6`, `wp`/`dwn`/`qtr` to `win_probability`/`down_number`/`quarter`)
confirmed the migration itself is correct, but found the spec cannot see the
failure mode that migration risked most.

## The gap

The spec asserts only on `snaps_off`, `snaps_def`, `opponent_nfl_team`,
`player_position`, and `targets` (merge survival). Nothing touches any column
derived from `quarter`, `down_number`, or `win_probability` — not `q1_snaps_off`,
not `q1_snaps_def`, not `snaps_neutral`, `snaps_neutral_early_down`, or
`snaps_low_prob`.

Worse, the fixture sets `down_number: 1` and `quarter: 1` identically on every
play, so the two are indistinguishable in the output. A transposition of the two
variables — the natural failure of a word-boundary `perl` replace across three
identifiers — would leave the spec 4/4 green.

No transposition occurred in `20e4a31f6`; this was verified by reading the diff
line by line. The gap is latent, not live.

## What shipped

Committed as `e765a6b07` — test-only, one file, not deployed.

- [x] The fixture now runs five plays whose `quarter` and `down_number`
      distributions have DIFFERENT shape (quarter 1/1/2/1 against down 2/1/1/1),
      so reading one column as the other changes the counts. One play sits below
      the neutral win-probability band, landing in `snaps_low_prob` and in
      neither down bucket.
- [x] Thresholds were read off the script, not guessed: `snaps_neutral` is
      `win_probability > 0.2 && < 0.8`, `snaps_low_prob` is `< 0.2`, and the
      early/late split is that band plus `down_number <= 2` / `> 2`.
- [x] Three new tests assert the per-quarter computed keys on both sides
      (`q1..q4_snaps_off`, `q1..q4_snaps_def`) plus `snaps_neutral`,
      `snaps_neutral_early_down`, `snaps_neutral_late_down` and
      `snaps_low_prob`. Every column was confirmed present in
      `db/schema.postgres.sql`.
- [x] The spec still executes the real insert; the existing four tests were
      updated only where the wider fixture changed their counts.
- [x] **Proven RED.** With `quarter` and `down_number` transposed in the script
      in a throwaway worktree, the four pre-existing tests still passed and all
      three new ones failed (`expected 2 to equal 1`, `expected 1 to equal +0`,
      `expected 2 to equal 3`). Full suite green at 3314 passing.
