Files
siftlode/backend/tests/test_migration_rerun_invalid_index.py
T
peter 4aaaaa7860 chore(comments): drop epic, sprint and review-round ids from the code
The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").

Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.

Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).

One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
2026-10-05 00:19:39 +02:00

54 lines
2.2 KiB
Python

"""A concurrent index build that failed part-way, then re-run, DB-lane.
CREATE INDEX CONCURRENTLY that fails leaves an INVALID index under its name, and alembic_version is not
stamped, so the next start runs the migration again. `IF NOT EXISTS` matched the name and kept the
leftover, which the planner never uses; 0095 then dropped the old channel_id index, leaving `videos`
with no usable one. A re-run now rebuilds the leftover and drops the old index only once the new one is
valid.
"""
from alembic import command
from alembic.config import Config
from sqlalchemy import text
from app.db import engine
def _index(name: str) -> tuple[bool, str] | None:
with engine.connect() as conn:
row = conn.execute(
text(
"SELECT i.indisvalid, pg_get_indexdef(i.indexrelid) FROM pg_index i "
"JOIN pg_class c ON c.oid = i.indexrelid WHERE c.relname = :name"
),
{"name": name},
).first()
return None if row is None else (bool(row[0]), row[1])
def _leave_invalid(name: str) -> None:
"""What a build that failed part-way leaves behind: the name taken, the index INVALID."""
with engine.connect().execution_options(isolation_level="AUTOCOMMIT") as conn:
conn.execute(text(f"CREATE INDEX {name} ON videos (id)"))
conn.execute(
text(f"UPDATE pg_index SET indisvalid = false WHERE indexrelid = '{name}'::regclass")
)
def test_a_rerun_rebuilds_an_invalid_leftover_before_dropping_the_old_index(db):
db.rollback() # CONCURRENTLY waits for every open transaction, this session's too
cfg = Config("alembic.ini")
command.downgrade(cfg, "0094_plex_genres_hu_everywhere")
try:
_leave_invalid("ix_videos_channel_pub_cover")
_leave_invalid("ix_videos_views_desc")
finally:
command.upgrade(cfg, "head")
cover = _index("ix_videos_channel_pub_cover")
assert cover is not None and cover[0], cover
assert "INCLUDE (duration_seconds" in cover[1]
assert _index("ix_videos_channel_pub_desc") is None
views = _index("ix_videos_views_desc")
assert views is not None and views[0] and "view_count DESC NULLS LAST" in views[1], views