---
title: Close the games-played appearance follow-ups
type: task
status: completed
description: >-
  Closed out what the games_played appearance repair left open. Ruled against regenerating archetype
  data and against a pre-2016 reader signal, both because the consumers do not exist; collapsed the
  two disagreeing variance computations onto one shared definition; relabelled snaps_pass PASS for
  receivers.
base_uri: user:task/league/close-games-played-appearance-follow-ups.md
created_at: '2026-09-24T19:36:42.110Z'
entity_id: 0e9c2244-e2f5-4010-a2e9-7d7c3d3d96ab
finished_at: '2026-09-24T20:16:16.627Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: Low
public_read: true
relations:
  - relates [[███████████████████████-█████-██████-██-█████-██████████████]]
  - relates [[████████████████████████-████████-█████-██-██████-██████-███████████]]
tags:
  - user:tag/league-xo-football.md
  - user:tag/software-task.md
updated_at: '2026-09-24T20:16:34.676Z'
visibility_analyzed_at: '2026-11-05T23:48:31.852Z'
---

The `games_played` repair landed and deployed on 2026-09-24 ([[███████████████████████-█████-██████-██-█████-██████████████]], league `cdc933b90`, `f109bfa09`, `9fd744b4b`, deployed at `df0ef5908`). This task holds what it left open: two decisions that are the operator's, one site still counting rows, and one undeployed commit.

None of it is urgent. Nothing here is a live defect on a served surface.

## Plan

- [x] **Decide whether to regenerate the archetype data** — RULED: do NOT regenerate. The premise that made this a scope decision was wrong. `player_archetypes` is read only by `libs-server/simulation/`, and that module has no caller outside test files and its own internals — no API route, no script, no crontab reaches it. The 31 lost QB classifications would land in a table nothing serves, so there is a cost and no corresponding benefit. Revisit only if the simulation path gains a live consumer, at which point regenerate before trusting a single row.
- [x] **Rule on `calculate-player-variance.mjs`, the one site still counting rows** — DONE at league `9e1bd0429`, and it was not one site. `libs-server/simulation/load-player-variance.mjs` held a second, independent implementation on the live cache-miss path, and the two already disagreed on three axes unrelated to appearances: the script filtered to REG and the loader did not, the script used the sample standard deviation and the loader the population one, and the script required three games while the loader accepted one. Both now call `libs-server/player-variance-sample.mjs`, which also excludes non-appearances. The duplication was the defect worth fixing; the appearance filter came along with it.
- [x] **Decide whether pre-2016 needs a reader-facing signal** — RULED: no code. The bound is already recorded where a session that could act on it will look — the trap sheet, and the comments in `player-gamelog-appearances.mjs`. Both derived tables (`player_variance`, `player_archetypes`) hold only 2023 through 2025, so no stored row is affected, and the surfaces a reader actually sees are not currently mixing the two eras in one comparison. A column- or UI-level marker would be carrying cost against a reader who does not exist yet.
- [x] **Deploy `9fd744b4b`** (the archetypes predicate change). PUSHED — confirmed on `origin/master`, so the hand-off note that it was unpushed is stale. It landed after the deploy commit `df0ef5908`, so the hosts do not carry it yet. Backend-only and in no crontab, so it rides the next deploy with no action; nothing needs doing here beyond letting that happen.
- [x] **Decide the `REC` over `snaps_pass` label** — RULED by the operator on 2026-09-24: `REC` was not accurate, because the label must communicate that the player was present on a pass snap and must not imply a route, a target or anything else about what they did on it. Changed to `PASS` at league `be74b5637`, which is what QB and RB already render for the same field, so all three snaps groups now agree. Single site, `app/views/components/player-selected-row/column-groups.js`.

## Two measured tails, recorded rather than planned

- **41 season rows from 2016 on carry non-zero points with zero participation evidence** — DIAGNOSED 2026-09-24, and the return-touchdown guess was wrong. Every case is a missing snap import. The largest is a 2025 kicker at 22 points with no special-teams snap row; the negative ones are a receiver's lost fumble. Two consequences: the appearance predicate has no KICKING arm, so a kicker whose snaps fail to import reads as absent despite scoring, and there is no scoring-provenance defect here to audit. Forty-one rows against millions, so recorded rather than fixed.
- **`player_variance` and `player_archetypes` hold rows computed under the OLD definitions**, 1,858 and 1,162 respectively, covering 2023 through 2025 only. Neither table has a live consumer, so neither was regenerated; both would need a rerun before anything trusts them. This is the same ruling as the archetype item above, applied to the table the variance change just made stale.
- **1,027 derived scoring rows have no parent gamelog**, across 16 pids, 15 of which hold 2002-2004 games that reach no consumer. The one live case shows the derived rows are not parented BY CONSTRUCTION: both format generators build their insert set from the format value path rather than from `player_gamelogs`, so a sweep would clear today's rows and next week would mint more. The repair belongs where the insert set is built. Reasoning is in the `retract_unproduced_gamelogs` docstring in `scripts/generate-player-gamelogs.mjs`.
