Skip to content

migrate: {reindex} rebuilds battle's indexes concurrently, one at a time - #644

Merged
jthingelstad merged 2 commits into
mainfrom
session/battle-reindex-op
Oct 21, 2026
Merged

jthingelstad merged 2 commits into
mainfrom
session/battle-reindex-op

Conversation

@jthingelstad

@jthingelstad jthingelstad commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Refs #630 (does not close it).

Jamie, 2026-10-21: "Approved: add an ops command to elixir-mcp and rebuild the battle table's indexes concurrently in production after the 10-23 maintenance".

What

A migrate op, {reindex} (services/migrate/src/ops-reindex.mjs). REINDEX CONCURRENTLY cannot run inside the migrate runner's transaction, so it is an op, as {vacuum} is.

  • Report (read, no lock): {"reindex": {"table": "battle"}}. Returns each index's size, scans, validity, the constraint it backs, the foreign keys that use it, and a bloat estimate. Also the heap size, the row estimate, and every invalid index, with _ccnew/_ccold leftovers marked.
  • Rebuild (WRITE, production lock): {"reindex": {"table": "battle", "index": "<name>", "apply": true}}. Runs REINDEX INDEX CONCURRENTLY on exactly one of the table's indexes, by quoted name. statement_timeout is 240 s (the Lambda times out at 300 s) and lock_timeout is 60 s. Returns the size before and after, ms, and validity after. It is refused while any index on the table is invalid.
  • Leftovers (WRITE): {"reindex": {"table": "battle", "drop_invalid": "<name>"}}. Runs DROP INDEX CONCURRENTLY on one INVALID index. It is refused for a valid index or for one a constraint needs.
  • battle is the only table on the allowlist. npm run op treats only the bare {table} form as a read.

The bloat estimate needs no extension. It uses reltuples, the pg_stats widths and the fillfactor. On test data it came within 7% of every freshly rebuilt index.

Docs

  • A row in ops.md beside {vacuum}, and a line in the ops skill's "Choosing the read".
  • docs/notes/2026-10-21-battle-reindex-op.md.
  • Two DECISIONS lines, both [Jamie, 2026-10-21]: shared_buffers follows RDS's own setting and nothing pins it (Operations and AWS; RDS warned of 88 MB at a restart, but after the 10-21 restarts it was still 180 MB); battle's indexes are rebuilt concurrently by {reindex} (Schema and migrations).
  • infra/template.yaml is unchanged: its comment that shared_buffers is the engine default is still true.

Tests

services/migrate/test/ops-reindex.test.mjs, on a scratch database:

  • a bloated battle_pkey is rebuilt valid and smaller, and both foreign keys follow it;
  • a real _ccnew leftover comes from a rebuild cancelled behind an open writer; rebuilds are refused while it stands, drop_invalid refuses the valid index and drops the leftover, and the rebuild then succeeds;
  • every refusal is covered;
  • the timeouts are held under the template's Lambda timeout.

npm run verify is green on Node 24 (32/32 units). e2e-needed.sh says false.

Deploy

No tool changed, so there is no acceptance family. The rebuild itself is not part of this PR. It runs after the 10-21 maintenance, one index per invocation, smallest first, when Jamie says.

🤖 Generated with Claude Code

The report ({"reindex": {"table": "battle"}}) reads each index's size,
scans, validity, the constraint and foreign keys it carries and a bloat
estimate from planner statistics, with any invalid _ccnew/_ccold
leftover. The rebuild ({"index": "<name>", "apply": true}) runs
REINDEX INDEX CONCURRENTLY on one of the table's indexes under a 240 s
statement timeout and a 60 s lock timeout, refused while any index on
the table is invalid; drop_invalid drops one invalid leftover
concurrently. battle is the only table. npm run op classes only the
bare report as a read.

DECISIONS gains two [Jamie, 2026-10-21] lines: shared_buffers follows
RDS's memory-pressure setting, and battle's indexes are rebuilt
concurrently by {reindex}. The template's shared_buffers comment cites
the first. Refs #630.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@jthingelstad
jthingelstad force-pushed the session/battle-reindex-op branch from eb4fe28 to 00ac016 Compare October 21, 2026 11:41
@jthingelstad
jthingelstad marked this pull request as ready for review October 21, 2026 11:41
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T11:42:57.143979Z 00ac016 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

The maintenance ran early, on 10-21, and shared_buffers is still the
engine default (23081 pages, about 180 MB) after both restarts. The
template comment goes back to saying so; the DECISIONS line records
only the decision (RDS's own setting, nothing pins it) and what the
restarts showed; the rebuild runs after the 10-21 maintenance.

Refs #630

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@jthingelstad
jthingelstad enabled auto-merge (rebase) October 21, 2026 11:48
@jthingelstad
jthingelstad merged commit 2dab9ab into main Oct 21, 2026
7 checks passed
@jthingelstad
jthingelstad deleted the session/battle-reindex-op branch October 21, 2026 11:50
@jthingelstad

Copy link
Copy Markdown
Owner Author

Deployed to production 2026-10-21T11:57:35Z (2026-10-21 06:57:35 CDT).

  • Commit: 2dab9ab6 (platform lane); this PR's: bfe8793c, 2dab9ab6
  • MCP contract: 11.13.3
  • JSON API: 3.2.1
  • Acceptance: not run
  • Timing: started 2026-10-21T11:56:36Z (2026-10-21 06:56:36 CDT); the CI gate waited 2 s, then 58 s to this record: build 2 s, migrate-push 4 s, stack 31 s, grants 2 s, public-stats 1 s, card-art 3 s, site 4 s, smoke 5 s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant