---
title: Extend the stored hit-rate precompute to season grain
type: task
status: draft
description: >-
  The custom hit-rate route grades player season totals, but
  scripts/calculate-historical-hit-rates.mjs still drops every season type to its no-path branch,
  gated by a spec. Design the season-grain write key and windows, then extend the precompute.
base_uri: user:task/league/extend-historical-hit-rates-to-season-grain.md
created_at: '2026-09-26T21:25:53.137Z'
entity_id: 0971f9b0-95ed-4e68-ac71-92fe3cd3b005
owner_identity_uri: █████████████████████████
priority: Low
public_read: true
relations:
  - follows [[user:task/league/grade-season-scope-prop-markets-as-hit-rates.md]]
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-09-26T21:25:53.137Z'
visibility_analyzed_at: '2026-11-05T23:49:14.635Z'
---

## Overview

Extend `scripts/calculate-historical-hit-rates.mjs` to season grain, so stored hit rates exist for the 21 `player_season_prop_types` the custom route already grades.

The route (`GET /players/:pid/hit-rate`) grades season totals over completed regular seasons since league `19a879579`. The precompute still drops every season type to its terminal no-path branch in `get_hits`. That exception is deliberate and gated: `test/scripts.calculate-historical-hit-rates-season-exception.spec.mjs` goes red the day a season type reaches a grading branch. Delete or invert that gate as part of this work.

## Why it is its own task

The precompute writes stored columns (`prop_market_hit_rates`) consumed by the markets routes, keyed by game. A season selection carries no esbid, so the write key, the stored windows (`last_five`, `current_season`, and the rest are game-grain), and the point-in-time as-of boundary all need a season-grain design before any code.

## Open questions

- Write key for a season selection with no esbid.
- Which stored windows mean anything at season grain. The route reads all completed seasons strictly before the selection's own season.
- Whether the markets routes need a season-grain reader at all, or whether the route's live reading is enough.

## Reuse

`build_completed_season_totals` and `calculate_player_season_hit_rate` (`libs-server/prop-hit-rate-sample.mjs`, `libs-server/prop-hit-rate.mjs`) are the season derivation. The precompute must call them rather than re-derive, per the agreement invariant in `libs-server/prop-hit-rate.mjs`.
