---
title: Build the NFL classification registry
type: task
status: completed
description: >-
  One league module defines every NFL class (game, team-game, drive, play, selection) with its
  values, definition, measurement and version; database constraints, film labels, a Python export
  and a generated knowledge-base reference derive from it.
base_uri: user:task/league/build-nfl-classification-registry.md
created_at: '2026-10-20T01:11:43.596Z'
entity_id: c5766a56-35df-43ec-8430-85b58a84422e
finished_at: '2026-10-20T01:43:58.833Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: High
public_read: true
relations:
  - subtask_of [[█████████████-██████████████-████-████-███-█████-███-██████████████-███████████]]
started_at: '2026-10-20T01:19:01.486Z'
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-10-20T01:43:58.833Z'
visibility_analyzed_at: '2026-11-05T23:48:27.972Z'
---

# Implementation Plan: Build the NFL classification registry

## Overview

- One league module defines every NFL class the platform, the betting kit and the film program use: its grain, axis, values, definition, how it is measured and its version. Every other vocabulary derives from it.
- Impact: a class has one spelling and one meaning everywhere, a database constraint or film label can no longer drift from the code that computes it, and the knowledge base reads a generated reference instead of hand-copied lists.
- Ordering: first child of [[█████████████-██████████████-████-████-███-█████-███-██████████████-███████████]]; the drive, game-class, vocabulary and film-page children build on it.

## Background

- League vocabularies today live in about eight places: `libs-shared/classify-nfl-team-game.mjs` (`SCRIPT_PATHS`, `WINDOW_READINGS`, `VOLUME_SHOCK_CAUSES`, classifier version 1), `libs-shared/constants/score-state-constants.mjs` (8 and 16 point cut points), `libs-shared/classify-selection-outcome.mjs` (`MISS_MECHANISMS`), `libs-shared/film-observation-labels.mjs` (the only labelled registry: label, title, value kind, closed values, validator), Postgres enums in `db/schema.postgres.sql`, CHECK constraints on `nfl_team_classification_gamelogs`, and filter params in `libs-shared/nfl-plays-column-params.mjs`.
- `db/tools/vocabulary-constrained-columns.mjs` catalogs CHECK `= ANY(ARRAY[...])` columns, and `db/gates/check-stranded-vocabulary-literals.mjs` rejects literals outside them; enums and free varchars are outside its reach.

### Assumptions

- `libs-shared/constants/index.mjs` is the barrel shared code already imports constants through (checked: file exists; unchecked: every consumer imports through it).
- The schema-export round trip regenerates CHECK constraints from `db/schema.postgres.sql`, so a generated constraint list can be diffed in a gate (unchecked; read the export tool before step two).
- Python tools in user-base can read a JSON file exported from the league repo at a fixed path (unchecked; confirm how `cli/nfl/*.py` resolve the league repo today).

## Design

- `libs-shared/nfl-classification/nfl-classification-registry.mjs` exports one entry per class: `class_name`, `title`, `grain` (`game`, `team_game`, `drive`, `play`, `selection`), `axis`, `definition`, `value_kind` (`enumerated`, `player`, `count`, `text`), `value_list` (each value with `value` and `definition`), `measurement_source` (`measured`, `film`, `judged`), `measurement_rule` (prose naming the computing module), `is_multi_valued`, `stored_column_list` (the `{ table, column }` pairs the values are stored in), `registry_version`.
- `title` and `value_kind` let the film label view derive from the registry; `stored_column_list` is what the vocabulary gate checks the database against.
- Code names a value through `name_nfl_classification_values` (`script_paths.within_one_score`) rather than spelling the literal.
- Derived artifacts: the film label set (`film-observation-labels.mjs` becomes a view over entries whose source is `film`), the CHECK constraint value lists (verified by the vocabulary gate), a JSON export for Python, and a generated knowledge-base reference document.
- Classes and rates: an entry defines what a game, drive or play IS. No entry carries a rate, a prior or a hit frequency (operator philosophy, classes curate and never price).
- Knowledge Base Impact: new generated `█████████████████████████████████████████████████`; `█████████████████████████████████████` labels row points at the registry; the query-trap sheet `guideline/nfl/league/query-traps/nfl-team-classification-gamelogs.md` names the registry as the vocabulary source.
- No scratch directory.

## Plan

- [x] **Registry module** with entries for every vocabulary the existing classifiers write (team-game script path, window reading, volume-shock cause, score-state margin band, miss mechanism, play classification, film labels). File: `libs-shared/nfl-classification/nfl-classification-registry.mjs`, exported through `libs-shared/constants/index.mjs`. Verify: a spec asserts every value in `SCRIPT_PATHS`, `WINDOW_READINGS`, `VOLUME_SHOCK_CAUSES`, `MISS_MECHANISMS` and the film label enumerations appears in the registry, and run the league suite.
- [x] **Existing modules read the registry.** `classify-nfl-team-game.mjs`, `classify-selection-outcome.mjs` and `film-observation-labels.mjs` import their value lists from it rather than declaring them. Verify: `rg -n "'led_by_two_scores'|'team_volume'|'single_high'" libs-shared` finds each literal only in the registry; league suite passes.
- [x] **Vocabulary gate covers the registry.** Sibling gate `db/gates/check-classification-registry-vocabulary.mjs`, in the cluster manifest, reading CHECK membership, CHECK containment and enum columns, so each CHECK-constrained column backed by a registry class must list exactly the registry values. Verify: removing one value from the registry reds the gate on `nfl_team_classification_gamelogs`.
- [x] **JSON export for Python** at `static-data/nfl-classification-registry.json`, written by a script and checked fresh by the gate. Verify: the export round-trips (`node` script writes it, a spec reads it back equal to the module).
- [x] **Generated knowledge-base reference** `█████████████████████████████████████████████████` (created once with `base entity create`, body regenerated by a script) listing every class by grain with its values and definitions. Verify: the generator is idempotent (second run, empty diff) and the document stays under 43,000 bytes.
- [x] **Knowledge base pointers**: update `█████████████████████████████████████` (labels row) and the team-classification query-trap sheet to name the registry. Verify: `rg -n "nfl-classification-registry" text/league guideline/nfl/league` finds both.
- [x] **Naming check**: run `db/tools/audit-schema-conformance.mjs` over any new identifier and the full-word rule of [[user:guideline/write/write-software.md]]. Verify: the audit passes.
