---
title: Refactor player_rankings tables to season-only
type: task
status: completed
description: >-
  Drop unused week, seas_type, and nfl_week_id columns from player_rankings_index and week from
  player_rankings_history; remove unused weekly-rankings data-view variant; delete dead
  import-fantasypros-weekly script. Unblocks the failing league-fantasypros-dynasty cron and
  prevents the same failure mode in import-fantasypros-draft.
base_uri: user:task/league/refactor-player-rankings-tables-to-season-only.md
created_at: '2026-05-02T22:46:08.963Z'
entity_id: 134ed272-e97c-451a-9121-df6caa82f3e4
finished_at: '2026-05-03T05:32:21.750Z'
observations:
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: High
public_read: true
relations:
  - relates [[████████████████████████-███-██████████-████-███████████]]
  - relates [[user:task/league/migrate-weekly-fields-to-single-nfl-week-id.md]]
  - relates [[██████████████████████-███-████-████-████████-███████]]
  - >-
    relates
    [[user:task/github/mistakia/league/309-refactor-implement-a-date-format-to-describe-a-nfl-season-week.md]]
started_at: '2026-05-03T05:17:22.049Z'
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-05-03T05:32:21.750Z'
visibility_analyzed_at: '2026-11-05T23:49:58.977Z'
---

# Implementation Plan: Refactor player_rankings tables to season-only

## Overview

- Remove unused `week`, `seas_type`, and `nfl_week_id` columns from `player_rankings_index`, and `week` from `player_rankings_history`. All 590k+ rows across both tables are de facto season-level (week=0) and have always been
- Drop the unused weekly-rankings data-view variant (6 fields, column-definitions branch, ranking-split test) that was wired up in [[user:task/league/migrate-weekly-fields-to-single-nfl-week-id.md]] but never received any data
- Collapse the `RANKING_NAMES_MAP` in `libs-shared/data-views-nfl-week-migration.mjs` so any saved-view migration of legacy ranking column IDs lands on the season variant only — no dangling references to deleted week-variant field IDs
- Delete `scripts/import-fantasypros-weekly.mjs` (broken since 9fb7ba74, never scheduled, never produces queryable data); future weekly ranking support should land in dedicated tables with their own keying
- Unblock the `league-fantasypros-dynasty` cron (3 consecutive Discord alerts, last 2026-05-02) and pre-empt the same failure mode in `import-fantasypros-draft` before its June-August schedule fires
- Re-export `db/schema.postgres.sql`, update repo docs and KB entities to reflect the new posture, deploy

## Background

### Failure trigger

- 2026-04-23 commit `9fb7ba74` made `player_rankings_index.seas_type` NOT NULL with no default and added a `rankings_reg_week_bound` CHECK
- 2026-04-29 commit `39a1eb5f` added `seas_type: 'REG'` to dynasty + draft import inserts to satisfy the new constraint
- The fix unblocked `_index` inserts but inadvertently broke `_history` inserts: the same insert object is spread into both tables, and `_history` doesn't have a `seas_type` column. Postgres returns 42703 (undefined column) on every dynasty run since 2026-04-26
- League-production was running pre-2026-04-29 code at the time of investigation; the `39a1eb5f` fix has since been deployed via `yarn deploy` (master HEAD `2939abdd`), but the underlying `_history` schema mismatch is still present and dynasty inserts still fail

### Empirical state of the data

- `player_rankings_index`: 138,809 rows, all `week=0`, 16 years, 18 ranking_types
- `player_rankings_history`: 451,305 rows, all `week=0`, 16 years, 8 ranking_types, up to 185 distinct timestamps per ranking_type (snapshot history)
- Zero weekly rankings have ever been written to either table

### Design intent vs. reality

- 9fb7ba74 introduced era-aware ███ ████ ████████ across many tables. Rankings tables were included for forward-compat. The Apr 24 schema dump dropped the prior `DEFAULT 'REG'` from seas_type and added the CHECK, hardening invariants for a feature path nobody had used
- Task [[user:task/league/migrate-weekly-fields-to-single-nfl-week-id.md]] split data-view ranking fields into "season" (filters `week=0`, `seas_type='REG'`) and "week" (filters by `nfl_week_id`) variants. The week variant compiles, tests pass, but there are zero rows it could ever match
- `scripts/import-fantasypros-weekly.mjs` was updated in 9fb7ba74 to write `seas_type` to `_index` and `_history`. It is not scheduled in any cron file, has no recent log evidence, and would crash on the same `_history` undefined-column error if it ever ran

### Audit surface

- **Schema** (`db/schema.postgres.sql`): table defs, UNIQUE on `(year, week, source_id, ranking_type, pid)` named `player_rankings_index_unique`, CHECK `rankings_reg_week_bound`, generated `nfl_week_id`, `idx_player_rankings_index_nfl_week_id`
- **Import scripts** (3 files): `scripts/import-fantasypros-{dynasty,draft,weekly}.mjs`
- **Data-view column definitions**: `libs-server/data-views-column-definitions/player-rankings-column-definitions.mjs` (season + week variant code paths; imports `resolve_single_nfl_week_id`, `decompose_nfl_weeks` used only by week path)
- **Data-view migration helper**: `libs-shared/data-views-nfl-week-migration.mjs` (`RANKING_NAMES_MAP` at L36-61 maps legacy column IDs to both `season` and `week` targets; `migrate_column_entry` at L114-141 branches on `week_val`)
- **Frontend data-view fields**: `app/core/data-views-fields/player-rankings-table-fields.js` (6 `create_player_week_rankings_field` blocks at L121-157, plus the helper `create_player_week_rankings_field` defined at L69)
- **Field labels**: `libs-shared/data-view-fields-index.mjs` does NOT contain `player_*_week_*ranking` entries — only legacy flat names (`player_average_ranking` etc. at L533-538). No edit needed here for the week-variant removal
- **Tests**: `test/data-views-ranking-split.spec.mjs` (asserts column-def exports + migration helper branching), `test/data-view-queries/player-rankings.json` (filters week=0, seas_type=REG; expected SQL hash will change)
- **Crontab**: `server/crontab-main/league-imports.cron` (dynasty L87, draft L90)
- **Repo docs**: `docs/data-views-system.md` "███ ████ ████████ Invariants" section, `docs/canonical-data-schemas.md`
- **User-base KB**: `███████████████████████████████████████████████████`, `task/league/migrate-weekly-fields-to-single-nfl-week-id.md`, `████████████████████████████████████████████████`, `task/github/mistakia/league/309-refactor-implement-a-date-format-to-describe-a-nfl-season-week.md`, `text/league/mistakia-league-postgres-tables.md`, `guideline/nfl-database-analysis.md`, `guideline/league-season-close-out.md`

### Operational context (per `repository/active/league/CLAUDE.md`)

- Schema changes are applied directly with `ALTER` on production, then `yarn export:schema` regenerates `db/schema.postgres.sql` as the source of truth (no incremental migration files)
- Deploy via `yarn deploy` (pulls + yarn install + pm2 reload on `league` and `league-worker-1`)

## Design

### High-level approach

Treat `player_rankings_index` and `player_rankings_history` as season-level rankings tables, removing artifacts of the era-aware week encoding that turned out to have no real consumers. Roll back the rankings-side of `9fb7ba74` and the rankings-side of [[user:task/league/migrate-weekly-fields-to-single-nfl-week-id.md]] in one cohesive change, leaving the unrelated `practice` and `nfl_*` table changes from those migrations intact.

Sequence to keep production continuously valid: schema first, then code targeting the new schema, then re-export and deploy. No migration script (per repo policy: ALTER directly, then `yarn export:schema`).

### Schema target

`player_rankings_index` final shape:

```sql
CREATE TABLE public.player_rankings_index (
    pid character varying(25) NOT NULL,
    pos character varying(4) NOT NULL,
    year smallint NOT NULL,
    min integer,
    max integer,
    avg numeric(5,2),
    std numeric(5,2),
    overall_rank integer,
    position_rank integer,
    source_id public.rankings_source_id NOT NULL,
    ranking_type public.ranking_type NOT NULL
);
-- UNIQUE (year, source_id, ranking_type, pid) named player_rankings_index_unique
```

Dropped: `week`, `seas_type`, `nfl_week_id` (generated), `rankings_reg_week_bound` CHECK, `idx_player_rankings_index_nfl_week_id`, prior UNIQUE on `(year, week, source_id, ranking_type, pid)`.

`player_rankings_history` final shape:

```sql
CREATE TABLE public.player_rankings_history (
    pid character varying(25),
    pos character varying(4) NOT NULL,
    year smallint,
    min integer,
    max integer,
    avg numeric(5,2),
    std numeric(5,2),
    overall_rank integer,
    position_rank integer,
    "timestamp" integer NOT NULL,
    source_id public.rankings_source_id,
    ranking_type public.ranking_type NOT NULL
);
```

Dropped: `week`. (No `seas_type` or `nfl_week_id` ever existed on this table.)

### Code structure

- **Import scripts**:
  - `scripts/import-fantasypros-dynasty.mjs`: drop `week: 0` and `seas_type: 'REG'` from inserts; update `onConflict` from `['year','week','source_id','ranking_type','pid']` to `['year','source_id','ranking_type','pid']`. Both `_index` and `_history` inserts use the same spread object — verify the cleanup leaves zero `week`/`seas_type`/`nfl_week_id` keys before commit
  - `scripts/import-fantasypros-draft.mjs`: same shape, same verification
  - `scripts/import-fantasypros-weekly.mjs`: delete entirely
- **Data-view column definitions** (`libs-server/data-views-column-definitions/player-rankings-column-definitions.mjs`):
  - Remove the week-variant code path (the branch filtering on `nfl_week_id`)
  - Simplify the season path: drop `.where('week', 0).where('seas_type', 'REG')` filters, since columns no longer exist
  - Net effect: one rankings code path keyed on `(year, source_id, ranking_type)`
  - Remove now-unused imports: `resolve_single_nfl_week_id`, `decompose_nfl_weeks` (and any other helper imports used only by the week path)
- **Data-view migration helper** (`libs-shared/data-views-nfl-week-migration.mjs`):
  - Collapse `RANKING_NAMES_MAP[*]` from `{season, week}` objects to plain string mappings to the season variant only — e.g., `player_average_ranking: 'player_season_average_ranking'`
  - Simplify the rankings branch in `migrate_column_entry`: always emit the season ID, drop `week`/`seas_type`/`single_week`/`single_seas_type` from params, remove the `is_season` conditional
  - Outcome: any legacy saved view that referenced `player_average_ranking` (with or without a `week`) now migrates to the season variant. Saved views already migrated to `player_week_*` (if any exist) need separate handling — see Pre-flight task
- **Data-view fields** (frontend):
  - `app/core/data-views-fields/player-rankings-table-fields.js`: drop the 6 `create_player_week_rankings_field` blocks (L121-157), drop the `create_player_week_rankings_field` helper itself (L69), keep only the season variant
- **Field-label index** (`libs-shared/data-view-fields-index.mjs`): no edit needed — file holds legacy flat names, not the split variants
- **Tests**:
  - `test/data-views-ranking-split.spec.mjs`: rewrite. Keep the season-variant column-definition assertions; delete the week-variant column-definition assertions (L16-76 affected); delete the week-branch migration tests (L78-112) since the migration helper no longer has a week branch. If the rewrite produces a trivial single-test file, fold it into a sibling test rather than keeping a one-test file
  - `test/data-view-queries/player-rankings.json`: must be regenerated AFTER `yarn export:schema` runs, so `test/global.mjs` reloads the new schema and the expected SQL is generated against the dropped columns. Alternatively, hand-edit the fixture's `expected_query` string to remove `"week" = 0 and "seas_type" = 'REG'` and re-snapshot the hash key

### Deployment sequence

- Apply ALTERs directly on `league_production` via `psql` over SSH
- From local repo: run `yarn export:schema` to regenerate `db/schema.postgres.sql`
- One commit on master containing: schema dump + import script changes + data-view changes + migration-helper change + test changes + script deletion + doc updates
- Push, then `yarn deploy`
- Manually trigger dynasty import on `league` to confirm green
- Watch next two scheduled dynasty runs (Wed/Sat 03:00 UTC) for clean exits and Discord alert clearance

### Integration points

- **Saved data views**: pre-flight a SELECT against the production `data_views` table for any view referencing the 6 specific week-variant ranking field IDs being deleted: `player_week_average_ranking`, `player_week_overall_ranking`, `player_week_position_ranking`, `player_week_min_ranking`, `player_week_max_ranking`, `player_week_ranking_standard_deviation`. If results are empty, no action. If non-empty, decide between (a) UPDATE swapping each occurrence to the season variant, (b) leaving for manual user fix
- **Rolling back**: dropped columns held no information (uniform week=0, seas_type=REG); recovery is just re-running ALTER ADD COLUMN with the prior defaults and redeploying old code
- **Worker server**: `league-worker-1` doesn't run rankings imports and doesn't query rankings tables — nothing to verify there beyond the standard `yarn deploy` reload

### Knowledge Base Impact

- **Domain entry**: rankings system has no dedicated entry document. Closest reference is `text/league/mistakia-league-postgres-tables.md`. No new entry justified
- **Affected ABOUT.md files**: none. Rankings tables aren't referenced from any ABOUT.md
- **Affected text entities**: `text/league/mistakia-league-postgres-tables.md` — update the schema rows for both ranking tables
- **Affected guidelines**: `guideline/nfl-database-analysis.md`, `guideline/league-season-close-out.md` — confirm whether rankings-import steps need revision; touch only if they reference the dropped columns
- **Affected task entities** (record-keeping `[updated]` observations rather than retroactive edits):
  - `███████████████████████████████████████████████████` — observation noting rankings-side rollback
  - `task/league/migrate-weekly-fields-to-single-nfl-week-id.md` — observation noting week variant removed as unused
  - `task/github/mistakia/league/309-refactor-implement-a-date-format-to-describe-a-nfl-season-week.md` — observation noting rankings tables no longer carry `nfl_week_id`
  - `████████████████████████████████████████████████` — review for relevance, observation if warranted
- **In-repo league docs** (mirrored by the code change commit): `docs/data-views-system.md` ███ ████ ████████ Invariants — remove rankings tables from the listed tables. `docs/canonical-data-schemas.md` — update rankings rows
- **Tag implications**: none (existing `league-xo-football` tag suffices)
- **Observation candidates**: a `[gotcha]` observation worth capturing — "`player_rankings_index` and `player_rankings_history` are written from a single insert object; their column sets must stay in lockstep when adding/removing fields." Attach to `text/league/mistakia-league-postgres-tables.md`
- **Relations**: none new

## Notes

- ALTER DROP COLUMN takes ACCESS EXCLUSIVE briefly but completes near-instantly without rewriting tuples; 451k `_history` rows are not a concern
- `scripts/postgres-backup.sh` references `player_rankings_history` for routine pg_dump; no change needed since column drops are reflected in the dump automatically
- Per `simplify-software-plan` guideline: this plan resists extending to a full "design new weekly_rankings table" effort. That can be planned when the second consumer (an actual weekly data source) materializes
- Per `write-javascript` guideline: import script edits preserve `#db`, `#libs-shared`, etc. aliases — no relative path traversal. ESLint will flag any imports that become unused after the week-path removal in column-definitions; clear them in the same edit
- The 3 import scripts share an identical insert pattern; tempting to extract a `insert_player_rankings({inserts, timestamp})` helper. Defer per rule-of-three — they currently differ in source, ranking_type derivation, and conflict semantics; the duplication is honest, not premature
- Plan reviewed via `/review-plan` on 2026-05-02; revision applied to address two critical findings (missing `data-views-nfl-week-migration.mjs` handling; spurious `data-view-fields-index.mjs` mention) and four notable findings

## Plan

### Setup & Preparation

- [x] **Pre-flight check for orphan saved views**
  - Result: 1 orphan found (view*id `5afeade6-d12f-434c-856c-f256a699f645`, "FantasyPros ECR", user 130). Contained `player_week_average_ranking` in `sort` and `columns` plus a corrupted `single_nfl_week_id: "2023_REG_WEEK*[object Object]"`. Migrated to `player_season_average_ranking`with`params: {ranking_source_id:['FANTASYPROS'], ranking_type:['PPR_REDRAFT'], year:[2023]}`. Re-query confirms zero remaining orphans.
  - Description: Query `data_views` table for any saved view referencing the 6 week-variant ranking field IDs being deleted
  - Purpose: Decide whether to migrate or drop orphan filters before removing the field definitions
  - Activities:
    - Field IDs to check: `player_week_average_ranking`, `player_week_overall_ranking`, `player_week_position_ranking`, `player_week_min_ranking`, `player_week_max_ranking`, `player_week_ranking_standard_deviation`
    - Run on production: `SELECT view_id, name, view_state FROM data_views WHERE view_state::text ~ 'player_week_(average|overall|position|min|max)_ranking|player_week_ranking_standard_deviation'`
    - If empty: proceed without action. If non-empty: surface to user and decide between (a) UPDATE swapping each occurrence to the corresponding `player_season_*_ranking` ID, (b) leaving for manual user fix

- [x] **Pre-flight grep coverage check**
  - Result: greps for `player_rankings_index|_history`, the 6 week-variant field IDs, and `RANKING_NAMES_MAP` reconcile with the audit list. Files touched will be the 3 import scripts, column-definitions, migration helper, frontend fields file, the two test files, schema dump (auto), and the two doc files. No new references surfaced.
  - Description: Re-run targeted greps for `player_rankings_history`, `player_rankings_index`, `nfl_week_id` on rankings, the 6 week-variant field IDs, and `RANKING_NAMES_MAP`
  - Purpose: Catch any reference the audit missed before opening the change set
  - Activities:
    - `grep -rn` across `app/`, `api/`, `libs-server/`, `libs-shared/`, `scripts/`, `docs/`, `test/`
    - Reconcile against the audit list; expand task list if new references surface

### Core Implementation

- [x] **Apply DDL on `league_production`**
  - Description: Execute the schema changes directly on production via `ssh league 'psql ...'`
  - Purpose: Establish new schema before deploying code that targets it
  - Activities:

  ```sql
  ALTER TABLE player_rankings_index DROP CONSTRAINT IF EXISTS rankings_reg_week_bound;
  ALTER TABLE player_rankings_index DROP CONSTRAINT IF EXISTS player_rankings_index_unique;
  DROP INDEX IF EXISTS idx_player_rankings_index_nfl_week_id;
  ALTER TABLE player_rankings_index DROP COLUMN nfl_week_id;
  ALTER TABLE player_rankings_index DROP COLUMN seas_type;
  ALTER TABLE player_rankings_index DROP COLUMN week;
  ALTER TABLE player_rankings_index ADD CONSTRAINT player_rankings_index_unique UNIQUE (year, source_id, ranking_type, pid);

  ALTER TABLE player_rankings_history DROP COLUMN week;
  ```

  - Validate via `\d player_rankings_index` and `\d player_rankings_history` immediately after

- [x] **Update import-fantasypros-dynasty.mjs**
  - Description: Remove `week` and `seas_type` from the inserts object; update onConflict key
  - Purpose: Match new schema; restore working dynasty insert into both tables
  - Activities:
    - Drop `week: 0` and `seas_type: 'REG'` lines from the insert object literal
    - Change `.onConflict(['year', 'week', 'source_id', 'ranking_type', 'pid'])` to `.onConflict(['year', 'source_id', 'ranking_type', 'pid'])`
    - Verify the post-edit insert object has zero `week`, `seas_type`, or `nfl_week_id` keys (the same object spreads into both `_index` and `_history` inserts; any residual will reproduce the 42703 error)

- [x] **Update import-fantasypros-draft.mjs**
  - Description: Same edits as dynasty, same verification
  - Purpose: Pre-empt the June-August failure mode
  - Activities: same key-removal verification as dynasty

- [x] **Delete scripts/import-fantasypros-weekly.mjs**
  - Description: `git rm` the file
  - Purpose: Remove broken, unscheduled, dead-end script. Future weekly support belongs in dedicated tables
  - Activities:
    - Confirm no live cron schedules it (already verified: no entries in `server/crontab-*/`)
    - Confirm no other code imports from it

- [x] **Update libs-server/data-views-column-definitions/player-rankings-column-definitions.mjs**
  - Description: Remove week-variant code path; simplify season path; clean unused imports
  - Purpose: One rankings query path keyed on `(year, source_id, ranking_type)`
  - Activities:
    - Delete the branch that filters on `nfl_week_id`
    - Remove `.where('week', 0)` and `.where('seas_type', 'REG')` from the remaining path
    - Remove now-unused imports: `resolve_single_nfl_week_id`, `decompose_nfl_weeks`, and any helper used only by the week path. ESLint will flag any that remain

- [x] **Update libs-shared/data-views-nfl-week-migration.mjs**
  - Description: Collapse `RANKING_NAMES_MAP` and simplify the rankings branch of `migrate_column_entry` so legacy column IDs always migrate to the season variant
  - Purpose: Prevent dangling references to deleted week-variant field IDs in any saved-view migration path
  - Activities:
    - Change `RANKING_NAMES_MAP[*]` entries from `{season, week}` objects to plain strings pointing at the season variant only (e.g., `player_average_ranking: 'player_season_average_ranking'`)
    - In `migrate_column_entry`, replace the `is_season` branching block with: assign `column_id = RANKING_NAMES_MAP[column_id]`, delete `params.week`, `params.seas_type`, `params.single_week`, `params.single_seas_type`, return
    - The `clean_legacy` helper, `resolve_single_identifier` helper, and `format_nfl_week_identifier` import remain in use by the practice/dfs/odds branches — leave them
    - Confirm the file's other consumers (`data-views.js`, `plays.js`, `data-view-storage/migrations.mjs`) still import valid exports

- [x] **Update app/core/data-views-fields/player-rankings-table-fields.js**
  - Description: Remove the 6 week-variant field definitions and the helper that creates them
  - Purpose: Frontend exposes only season-level ranking fields
  - Activities:
    - Delete the 6 `create_player_week_rankings_field({...})` entries at L121-157
    - Delete the `create_player_week_rankings_field` helper definition at L69 (becomes unused after the entries are removed)
    - Verify the file still exports the 6 season fields and any non-week helpers

- [x] **Update tests**
  - Description: Adjust `test/data-views-ranking-split.spec.mjs` and `test/data-view-queries/player-rankings.json`
  - Purpose: Match new field set and query shape
  - Activities:
    - In `data-views-ranking-split.spec.mjs`: keep the season-variant column-definition assertions (L16-76 region); delete the week-variant column-definition assertions and the week-branch migration tests (L78-112). If the rewrite produces a trivially small file, fold it into a sibling test instead of keeping a one-test file
    - For `test/data-view-queries/player-rankings.json`: hand-edit the `expected_query` string to remove `"week" = 0 and "seas_type" = 'REG'` and any associated WHERE-clause AND glue. The hash key (`expected_query_hash` field) will need to be recomputed; either compute manually from the updated SQL or run the test with the new schema dump applied (test/global.mjs reloads from `db/schema.postgres.sql`) and copy the failure's actual hash into the fixture
    - Run `yarn lint` then `yarn test --reporter min test/data-views-ranking-split.spec.mjs test/libs-server.data-view-queries.mjs` locally; both must pass

- [x] **Re-export schema dump**
  - Description: Run `yarn export:schema`
  - Purpose: Sync `db/schema.postgres.sql` (source of truth) with production reality. Must run AFTER the production DDL has been applied and BEFORE running the data-view-queries test against the new schema
  - Activities:
    - Verify the diff matches expectations: only the rankings tables, related index, CHECK, and UNIQUE should change
    - Re-run any failing data-view-queries fixture once dump is in place

- [x] **Update repo docs**
  - Description: `docs/data-views-system.md` and `docs/canonical-data-schemas.md`
  - Purpose: Keep developer docs aligned with schema
  - Activities:
    - In `docs/data-views-system.md` "███ ████ ████████ Invariants": remove rankings tables from the listed-tables section; keep practice and nfl\_\* references
    - In `docs/canonical-data-schemas.md`: update the rankings rows to match new column lists

- [x] **Single commit and push**
  - Description: One commit containing schema dump + script edits + script deletion + data-view edits + migration-helper edit + frontend edit + test edits + doc edits
  - Purpose: Atomic change so post-deploy state is internally consistent
  - Activities:
    - Run `yarn lint` and `yarn test --reporter min` locally before committing; lint must pass with zero unused-import warnings on the touched files
    - Commit message body should reference this task entity and the original failure (`league-fantasypros-dynasty` alert)

- [x] **Deploy via `yarn deploy`**
  - Description: Standard deploy to `league` and `league-worker-1`
  - Purpose: Land the code change on the same servers that just received the DDL

- [x] **Manually trigger dynasty import on `league`**
  - Description: SSH and run the production dynasty import command once with `--ignore_cache`
  - Purpose: Confirm green path immediately rather than waiting for the next scheduled run
  - Activities:
    - `ssh league` and run `NODE_ENV=production node scripts/import-fantasypros-dynasty.mjs --ignore_cache` from the production checkout, using the host's Node install
    - Confirm exit 0 and rows inserted into both `_index` and `_history`

### Knowledge Base Updates

- [x] **Update `text/league/mistakia-league-postgres-tables.md`**
  - Description: Adjust the schema descriptions for both rankings tables and add a `[gotcha]` observation
  - Purpose: KB reflects the schema actually in production
  - Activities:
    - Replace the column lists for `player_rankings_index` and `player_rankings_history`
    - Add a `[gotcha]` observation noting the index/history insert-object coupling

- [x] **Add `[updated]` observations to four prior task entities**
  - Description: Annotate prior migration tasks with a one-line note pointing back at this task
  - Purpose: Preserve historical record without retroactive content edits
  - Targets:
    - `███████████████████████████████████████████████████`
    - `task/league/migrate-weekly-fields-to-single-nfl-week-id.md`
    - `task/github/mistakia/league/309-refactor-implement-a-date-format-to-describe-a-nfl-season-week.md`
    - `████████████████████████████████████████████████` (if relevant — read first)

- [x] **Review and (if needed) update `guideline/nfl-database-analysis.md`**
  - Description: Touch only if rankings descriptions reference dropped columns
  - Purpose: Keep guideline aligned with reality

- [x] **Review and (if needed) update `guideline/league-season-close-out.md`**
  - Description: Touch only if rankings-import steps reference dropped columns or the deleted weekly script
  - Purpose: Keep season close-out runbook accurate

### Validation & Review

- [x] **Watch next two scheduled dynasty runs**

- [x] **Confirm draft job posture for June rollover**
  - Relying on the existing Discord alert pipeline. The draft script edit mirrors the dynasty edit exactly (same insert object, same onConflict key), and the dynasty manual trigger validated the shared shape. No separate snooze task needed.
