Skip to content

fix(db): auto-migrate prebuild-guarded indexes on small databases - #8802

Merged
TheSentinel454 merged 6 commits into
mainfrom
elrond/auto-migrate-artifact-indexes
Nov 5, 2026
Merged

TheSentinel454 merged 6 commits into
mainfrom
elrond/auto-migrate-artifact-indexes

Conversation

@TheSentinel454

@TheSentinel454 TheSentinel454 commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Migrations 0076, 0078 and 0081 raise an exception on any table with at least one row unless its index was prebuilt with CREATE INDEX CONCURRENTLY. A relay that runs migrations at startup (BUZZ_AUTO_MIGRATE, on by default in the Helm chart) and has data in those tables therefore crash-loops on upgrade:

migration error: while executing migration 81: error returned from database:
prebuild idx_nip_fi_profile_heads_names concurrently; see docs/profile-search.md

0081 (#9019) hits every auto-migrating relay that has published NIP-FI verified profiles. 0076/0078 (#8523) hit any relay with artifact data or channel members. Each of these tables is small enough on such relays that a plain index build takes milliseconds.

The root cause is docs/database.md Rule 6. It told authors that an index on a populated table MUST be built concurrently by an operator ahead of time, so migrations were written to refuse populated tables. With auto-migration that refusal is a crash loop, not a safe stop.

Fix

The migrations are already applied on some databases, so they can't be edited: sqlx would reject the changed checksums. Instead, run_migrations_locked builds their missing indexes first. For each entry in INLINE_INDEX_BUILDS (0076, 0078, 0081), it runs migrations through the version before it, then builds any missing index.

Each build is a plain CREATE INDEX in its own transaction, under the same 1s lock_timeout and 5s statement_timeout the migrations use. That is the bounded inline build 0049 already does:

  • Small populated databases upgrade the same way empty ones do.
  • Large databases still fail closed. Only a lock or statement timeout (55P03 / 57014) gets the "prebuild concurrently" hint, pointing at that migration's own doc. Other errors pass through unchanged. The blocked migration is not recorded.
  • Prebuilt indexes are found with to_regclass and skipped before CREATE INDEX, so deployments that prebuilt concurrently never request the writer-conflicting lock.
  • Invalid prebuilt indexes are left for the migration to reject, as before.

CONCURRENTLY is not used in this path. The runner holds the migration advisory lock, and another replica blocked on that lock holds a snapshot that a concurrent build would wait on.

Rules

  • docs/database.md Rule 6: with BUZZ_AUTO_MIGRATE on, every migration must apply its own change on a populated database and must never refuse one because it has rows. A new index is built inline under the migration's budgets. Only deployments that apply migrations out of band (auto-migration off) prebuild concurrently.
  • Root AGENTS.md (step 4) and migrations/AGENTS.md repeat the never-refuse rule.
  • docs/artifact-sync-deployment.md and docs/profile-search.md describe the startup behavior first and the concurrent prebuild as the out-of-band path.

Tests

  • populated_database_auto_migrates_through_every_migration (Postgres) migrates to 0075, seeds artifact rows, and checks four phases:
    1. Lock held: while a writer lock is held, the 0076 build fails closed.
    2. Index prebuilt: with the 0076 index prebuilt, the build is skipped.
    3. Partial 0078: a blocked 0078 build keeps the builds before it committed.
    4. Verified profile seeded: with a verified profile head inserted before 0081, a final startup succeeds. It asserts that the applied versions equal every embedded migration and that all six indexes are valid, ready and live.
  • frozen_prebuild_guards_have_inline_builds (no database) scans migrations/. It fails if any migration refuses a populated table (RAISE EXCEPTION 'prebuild …) without an inline build, and if a new guard is added.
  • migration_execution_cannot_bypass_schema_destruction_lock allows exactly one production run_to, inside run_migrations_locked.

What got simpler

  • Auto-migrating relays no longer need a manual, operator-only prebuild step for small deployments. That restores the chart README's contract that helm upgrade is the whole upgrade procedure.
  • Rule 6 no longer steers authors toward refusing populated tables, and a test enforces that.
  • The change adds one table-driven step for three frozen migrations and no new configuration.

🤖 Generated with Claude Code

@TheSentinel454
TheSentinel454 marked this pull request as ready for review October 30, 2026 20:50
@TheSentinel454
TheSentinel454 requested a review from a team as a code owner October 30, 2026 20:50
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Oct 30, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated, security-focused review generated by Codex.
Use it as a supplement to human review; false positives are possible.

Scope

  • Exact PR diff: ec21753e1b4ca3cd0f208b5fb42cb22a1e29a433...a481b5bbd5c157d49cd8f78d60e43014272e9c44
  • Model: gpt-6.1-sol

💡 Click "edited" above to see earlier reviews for this PR.


Review Summary

Overall Risk: NONE

No concrete security, correctness, or reliability issues found in the authorized PR range.

Findings

No concrete security, correctness, or reliability findings were identified.

Notes

  • Review used read-only source and history inspection. Builds and tests were not run.

Generated by Codex Security Review |
Requested by: @TheSentinel454 |
Workflow run

@github-actions github-actions Bot removed the codex-security-review-current The posted Codex security review matches its recorded range. label Oct 30, 2026
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Oct 30, 2026

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated review at exact head 538cda70edc88e4d5778a7475ea35b30d5a3537e (base f3a7bab098a530ba12b909cb7121b4fa9ce70731). No blocking findings.

The staged runner holds up. With sqlx 0.9, run_to(target) only limits which pending migrations get applied. On a database already at 76–78 the extra run_to calls just validate checksums, and the _sqlx_migrations check skips the builds. A dirty database or one with unknown migrations fails before any build runs. All five definitions in INLINE_INDEX_BUILDS produce exactly the pg_get_indexdef strings 0076 and 0078 verify, including the WHERE (source_channel_id IS NOT NULL) predicate. Each build commits on its own on the connection that keeps holding the schema/destruction lock, and a failed build rolls back without leaving an invalid index behind. buzz-admin migrate goes through db.migrate() → run_migrations, so the deployment doc is right that it builds the indexes too.

We also ran it against a throwaway Postgres 17. Both new tests pass. A real upgrade works too: apply the base's SQL migrations 1–75, seed artifact heads, revisions and a membership, then run the head's run_migrations. It reaches 78 with all five indexes valid, ready and live, and existing rows are unchanged. A repeat startup and two simultaneous migration calls both succeed. A same-named index with the wrong definition fails closed at 75 with the documented error, and the retry succeeds after dropping it. That upgrade also covers the path the new test doesn't: its final phase prebuilds the 0076 index, so the test never shows a successful inline build of that one.

MINOR (docs): docs/database.md now contradicts itself. Rule 6 still says an index on a populated table MUST be built CONCURRENTLY, and the next sentence says the migration builds a missing one inline. Rule 3 says a migration MUST NOT scan a table while holding a write-blocking lock, and a plain CREATE INDEX does exactly that. A future author can't satisfy all three. It'd be clearer to make the bounded inline build an explicit exception in both rules, keep the concurrent prebuild for tables too big for the budget, and move the "0076 and 0078 did" history into docs/artifact-sync-deployment.md. migrations/AGENTS.md should get the same wording.

MINOR (docs): docs/artifact-sync-deployment.md still opens with "For a populated database, first build the revision lookup index outside a transaction" and still says 0078 "refuses a populated table whose index is missing". Both are now true only for direct SQL application. Saying up front that startup migration handles small databases, and the concurrent prebuild is for large ones, would keep operators from doing a manual step they no longer need.

MINOR: build_indexes_before_migration maps every sqlx::Error to "migration N blocked … prebuild them concurrently". That advice is wrong for a dropped connection or a permission error. The underlying error is included, so this isn't misleading for long. Still, adding the prebuild hint only for lock or statement timeouts (SQLSTATE 55P03 / 57014) and passing other errors through unchanged would be more accurate.

@ShapedTime

Copy link
Copy Markdown

Data point from a self-hosted relay that hit this on main-20261102025339-d342cf1 (chart 0.1.11, Postgres 18.6, BUZZ_AUTO_MIGRATE=true). Two things that may affect how urgent this is:

It doesn't take any artifact data. The description scopes this to databases with artifact rows, but 0078 also covers channel_members_sync. Both of our artifact tables were empty, so 0076 passed, and then 0078 stopped on channel_members, which had 291 rows:

migration error: while executing migration 78: error returned from database:
prebuild channel_members_sync concurrently; see docs/artifact-sync-deployment.md

So a relay with a single channel member hits it, which is effectively every deployment in use.

A failed upgrade can't be rolled back by changing the image. Migrations commit one at a time, so 0052 to 0077 were already recorded when 0078 failed. The image we came from then refuses the database:

migration 52 was previously applied but is missing in the resolved migrations

With a rolling update the old pod keeps serving, so this looks fine until that pod restarts, and reverting the tag doesn't help. We confirmed that message by running the old image's buzz-admin migrate against a copy of the schema, not by restarting the production pod.

Workaround, for anyone landing here from that error: build the four indexes from docs/artifact-sync-deployment.md with psql. The doc then says to run buzz-admin migrate, but a crash-looping pod has nothing to exec into, and it isn't needed: the relay applied 0078 to 0080 itself on its next start and came up Ready.

From reading the diff, indexes prebuilt this way are skipped by the to_regclass check, and a database already at 0078 skips the builds entirely, so the workaround shouldn't conflict with this PR.

TheSentinel454 and others added 3 commits November 4, 2026 16:51
Migrations 0076 and 0078 refuse any populated table whose index was not
prebuilt concurrently, so every auto-migrating relay with artifact data
crashloops on upgrade, including the Helm chart default. Both migrations
are checksum-frozen, so the startup runner now builds their missing
indexes first under the same 1s lock and 5s statement budgets migration
0049 uses. Small databases upgrade like empty ones; large ones still fail
closed with an error pointing at docs/artifact-sync-deployment.md, and
prebuilt indexes are skipped before CREATE INDEX takes its lock.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Luke Tornquist <tornquist@squareup.com>
Review follow-up: one transaction kept every earlier ShareLock until the
last build committed, so writes to artifact_heads could stay blocked across
all four 0078 builds. Commit each build on its own, and describe partial
progress accurately in the deployment doc and test.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Luke Tornquist <tornquist@squareup.com>
…usals

Migration 0081 refuses a populated nip_fi_profile_heads whose name index
was not prebuilt, so every auto-migrating relay with verified profiles
crash-loops on that version. The startup runner now builds its index
first, like 0076 and 0078, under the same bounded budgets.

Rule 6 now says a migration applies its own change on a populated
database and never refuses one; operator prebuilds are an option for large
databases, not a precondition. A source test rejects any migration that
refuses a populated table unless it is a frozen one with an inline build,
and the populated upgrade test boots a database with data through every
embedded migration. The budget-exceeded hint now applies only to lock and
statement timeouts.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Luke Tornquist <tornquist@squareup.com>
@TheSentinel454
TheSentinel454 force-pushed the elrond/auto-migrate-artifact-indexes branch from 538cda7 to 64cce23 Compare November 4, 2026 21:58
@github-actions github-actions Bot added codex-security-review-current The posted Codex security review matches its recorded range. and removed codex-security-review-current The posted Codex security review matches its recorded range. labels Nov 4, 2026
@TheSentinel454 TheSentinel454 changed the title fix(db): auto-migrate artifact sync indexes on small databases fix(db): auto-migrate prebuild-guarded indexes on small databases Nov 4, 2026
With auto-migration on, migrations are the whole upgrade procedure, so
an operator prebuild is only for deployments that apply migrations out of
band. Drop the separate populated-upgrade testing rule; the populated
boot test and the prebuild-guard source test cover it.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Luke Tornquist <tornquist@squareup.com>
@github-actions github-actions Bot removed the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 4, 2026
The artifact test's run_migrations_through(80) bypasses the startup
runner's inline builds, so 0078 refused its seeded rows before 0081 was
reached. Seed verified profiles in their own test from 0080 instead.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Luke Tornquist <tornquist@squareup.com>
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 4, 2026
Rule 3 forbade any write-blocking scan, contradicting Rule 6's bounded
inline CREATE INDEX. Limit it to large tables and allow the budgeted
build. State that the prebuild-guard lint matches only its literal
wording, and that 0078 refuses populated tables only when applied as SQL.

Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Luke Tornquist <tornquist@squareup.com>
@github-actions github-actions Bot removed the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 4, 2026
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 4, 2026
@TheSentinel454

Copy link
Copy Markdown
Contributor Author

🤖 Thanks Will — all three addressed at a481b5b: Rules 3/6 reconciled (bounded inline build is the explicit exception; CONCURRENTLY prebuild only when auto-migrate is off), artifact-sync doc leads with the startup build, and the prebuild hint is limited to SQLSTATE 55P03/57014 with other errors passed through. This also covers 0081 now.

loganj added a commit that referenced this pull request Nov 5, 2026
Main took 0081 and 0082, so the migration is now 0083.

With BUZZ_AUTO_MIGRATE on, a migration that refuses a populated table
crash-loops every relay with data (#8802, docs/database.md Rule 6). The
migration no longer refuses a channels table with rows. As 0049 does, it
skips CREATE when to_regclass finds a prebuilt index, else builds the
index with a plain CREATE UNIQUE INDEX under the 1s lock and 5s statement
budgets, then verifies its definition and flags. A busy or very large
table fails on those budgets, records nothing, and the relay retries at
its next start.

It still refuses to run while listed duplicates remain: the index cannot
exist over them, and the renames must go through the relay.

Tests that migrate a populated database no longer prebuild the index. The
listed-name migration test now checks that a held channel writer makes
the inline build fail on its lock budget, and that a populated table then
migrates with no operator step. The rollout doc makes the concurrent
prebuild an out-of-band option only.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
TheSentinel454 pushed a commit that referenced this pull request Nov 5, 2026
## Summary

Stacked on #8782 (merged), which makes
the relay refuse a second open channel with a name that another channel
in the community already has. That check lives in relay code, so an
older relay, a direct database write or a missed code path can still
create a duplicate.

This PR adds the same rule to the database: a unique index on channel
name, ignoring case, for the channels that show in the channel list.
With the index in place, a duplicate fails at the write, whatever wrote
it. The relay's own name check from
#8782 is no longer needed, so this PR
removes it. Clients still get the same refusal, `invalid: an open
channel named "…" already exists`.

The migration builds the index itself, also on a populated `channels`
table, so an auto-migrating relay upgrades with no operator index step
(the rule from #8802). It still
refuses to run while duplicate names remain, because the index cannot
exist over them. `docs/channel-name-uniqueness-deployment.md` gives the
full rollout.

## Details

- **The index** (migration `0083_channels_listed_name_unique.sql`):
  ```sql
  CREATE UNIQUE INDEX idx_channels_listed_name
      ON public.channels (community_id, lower(name))
      WHERE visibility = 'open' AND NOT unlisted
        AND channel_type IN ('stream', 'forum') AND deleted_at IS NULL;
  ```
It covers open, not unlisted streams and forums that are not deleted,
archived ones included. Private channels, DMs and unlisted channels may
still repeat names.
- **The migration builds the index inline, as `0049` does.** When
`to_regclass` finds no index, it runs a plain `CREATE UNIQUE INDEX`
under `lock_timeout` 1s and `statement_timeout` 5s. On a busy or very
large table it fails on those budgets, records nothing, and the relay
retries at its next start. When the index already exists (a concurrent
prebuild), it skips `CREATE` so it never requests the write-blocking
lock. In both cases it then checks that the index is valid, ready and
has the exact expected definition.
- **One refusal stays: duplicate names.** The migration refuses to run
while listed duplicates remain, and its error names the rename script.
The renames must go through the relay so clients get the new kind:39000,
and a migration must not change rows (`docs/database.md` Rule 3). This
is the "fails closed until its repair has run" case in
`migrations/AGENTS.md`, so the writer release from
#8782 and the rename are a required
stop.
- **Relay.** A write that takes the name of a concurrent, uncommitted
write waits for it, and fails if that write commits. So the post-write
check and the per-name lock from #8782
are removed. The store already maps the index violation to the same
"name taken" error.
- **Desired-state schema.** `schema/tables/public/channels.sql` has the
same index, and the schema parity test compares its live shape between
the desired-state schema and the migrations.
- **Rollout** (`docs/channel-name-uniqueness-deployment.md`), in order:
1. Deploy #8782 and wait until no
older relay pod serves.
2. Rename the existing duplicates in each community with that PR's
script, while relays keep serving. The script needs `psql` and
`python3`, and the operator key must be a member of each community. The
doc covers archived communities and communities being deleted.
  3. Confirm that no duplicate remains.
4. Only for a deployment that migrates out of band and is too large for
the budgets: build the index with `CREATE UNIQUE INDEX CONCURRENTLY` and
verify it.
5. Deploy this release. With auto-migration on, the relay applies 0083
at startup. With it off, run `buzz-admin migrate` first, never the file
through `psql`.

Rollback goes to the #8782 release
only. Keep the index, and keep auto-migration off.
- **Test fixtures.** Tests that inserted two open channels with one name
now use distinct names. Tests that migrate a populated database through
0083 no longer prebuild the index.

### Related issue

None found. Follows #8782.

### Testing

- Migration tests (`listed_channel_name_postgres_tests.rs`) start from a
database migrated through 0082:
  - With duplicates, 0083 fails and changes nothing.
- After the rename plan is applied, a channel writer that holds its lock
makes the inline build fail on the 1s lock budget, with nothing
recorded.
- With no writer, the populated table migrates with no prebuild, and a
raw duplicate insert fails on the index.
- An index with a different definition, and an invalid one, are refused.
A valid prebuilt index is accepted, and not replaced, while another
transaction is writing to `channels`.
- The store and relay name tests from
#8782 pass with the relay check
removed: the index refuses the duplicate, and the client still gets
`invalid:`.
- The rename plan and script tests from
#8782 run on a database at 0082, the
state the script runs in.
- Local Postgres runs on `108737dc0`, one fresh database per test as the
nextest wrapper does: 38 of 40 buzz-db migration-lane tests pass (both
listed-name tests, the migration parity test, the thread-window and
invite-upgrade tests that migrate populated databases through 0083). The
2 `event_follow_up` contract tests fail locally the same way on main.
All 49 buzz-db channel and channel-member store tests pass.

### Database review checklist

- [x] Phase: contract. Before it:
#8782 (writer release, required stop)
and its rename script. Nothing after it.
- [x] No trigger, function, procedure, rule or foreign key.
- [x] No migration mutates rows. The renames happen before it, through
the relay, with the script in #8782.
- [x] Never refuses a table because it has rows. Fails closed only with
duplicates (repair not run) or with an invalid or different index; then
0083 raises and the relay does not start. The release notes must name
the release that contains #8782 as a
required stop.
- [x] Rule 4: `migrations/`, `schema/tables/public/channels.sql` and the
parity test. A live catalog comparison covers the index.
- [x] Deployed relay: the #8782 relay
answers `invalid:` beside the index (its tests pass with the index
present). A relay older than that still writes, but gets a database
error, not `invalid:`, for a duplicate. That is why
#8782 is a required stop.
- [x] Timeouts and index build: `lock_timeout` 1s, `statement_timeout`
5s. The migration builds the index inline (plain `CREATE UNIQUE INDEX`,
skipped when `to_regclass` finds a prebuilt one). Only out-of-band
deployments too large for the budgets prebuild it with `CREATE UNIQUE
INDEX CONCURRENTLY` (doc step 4).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated review at exact head a481b5bbd5c157d49cd8f78d60e43014272e9c44 (base ec21753e1b4ca3cd0f208b5fb42cb22a1e29a433). No blocking findings.

The three notes from the last review are all addressed. Rules 3 and 6 now agree, the artifact sync doc describes startup behavior first, and the prebuild hint only appears on a lock or statement timeout (55P03 / 57014).

The new 0081 entry in INLINE_INDEX_BUILDS is byte-for-byte the CREATE INDEX … USING gin (%s) string that 0081 checks with pg_get_indexdef. It's a GIN to_tsvector('simple', …) expression index with no predicate or extension dependency. The staged sequence (through 75, build 76, through 77, build 78, through 80, build 81, then the rest) is correct for fresh databases, ones already at 76–81, and dirty ones: with sqlx 0.9, run_to caps which pending migrations run, and dirty history fails before any build. frozen_prebuild_guards_have_inline_builds can't pass on an empty scan, because it also pins the list to [76, 78, 81]. Adding a temporary 0083 with a 'prebuild …' guard makes it fail.

We also ran it against a throwaway Postgres. All three new tests pass. A real upgrade works too: apply the base's migrations through 0080, seed a verified profile head, artifact heads/revisions and a channel member, then run the head's run_migrations. It reaches 0082 with the 0081 index valid, ready and live, and every seeded row unchanged. A restart is a no-op. While a writer lock is held on nip_fi_profile_heads, startup fails after about 1s with the 0081 hint pointing at docs/profile-search.md. 0081 isn't recorded and no partial index is left, and the retry succeeds once the lock is released. With a correct index prebuilt, startup succeeds even while the writer lock is still held, and the index keeps its OID, so the build was skipped. A same-named index with the wrong definition fails closed at 0081.

MINOR (docs): A large relay with auto-migration on that goes over the budget is told to "prebuild them concurrently as described in docs/profile-search.md" (or docs/artifact-sync-deployment.md). Those docs and Rule 6 now present the concurrent prebuild as the step for deployments with auto-migration off. That leaves an operator who hits the error on an auto-migrating relay unsure whether the procedure applies to them. One sentence in each doc saying an auto-migrating relay that fails the budget can prebuild concurrently and restart would fix it. Same gap in docs/thread-window-deployment.md, which Rule 6 links to: lines 12–16 still say all brownfield deployments must prebuild before starting the relay. That intro should get the same small/auto-migrating vs. large/out-of-band split.

MINOR (PR description): The Tests section describes a single four-phase populated_database_auto_migrates_through_every_migration. The code now has two tests: populated_artifact_tables_auto_migrate_through_every_migration and populated_verified_profiles_auto_migrate_through_every_migration.

@TheSentinel454
TheSentinel454 merged commit ff15c34 into main Nov 5, 2026
90 checks passed
@TheSentinel454
TheSentinel454 deleted the elrond/auto-migrate-artifact-indexes branch November 5, 2026 18:52
bradseiler added a commit that referenced this pull request Nov 5, 2026
…-media

* origin/main:
  fix(mobile): offer a new identity beside saved keys on unclaimed accounts (#9107)
  fix(desktop): show upgrade guidance (BUZZ-517) (#9033)
  fix(mobile): skip the read-state snapshot when nothing needs publishing (#9093)
  fix(mobile): keep verified names on screen in channels with over 1,024 members (#9111)
  mobile: reuse channel message rows that did not change (#9115)
  fix(mobile): back off push bootstrap retries (#9092)
  fix(mobile): keep reply counts on screen while a reconnect catches up (#9100)
  fix(mobile): inflate gzip read-state snapshot responses (#9089)
  perf(relay): cache the community-active check on socket admission (#9109)
  fix(db): auto-migrate prebuild-guarded indexes on small databases (#8802)
  docs: mark desktop/ as the deprecated Buzz 0.X app (#8840)

Signed-off-by: Brad Seiler <seiler@squareup.com>
wpfleger96 added a commit that referenced this pull request Nov 5, 2026
…dary

* origin/main:
  fix(mobile): focus the search field when search opens (#9120)
  perf(mobile): validate each verified profile once, not on every publish (#9101)
  fix(mobile): offer a new identity beside saved keys on unclaimed accounts (#9107)
  fix(desktop): show upgrade guidance (BUZZ-517) (#9033)
  fix(mobile): skip the read-state snapshot when nothing needs publishing (#9093)
  fix(mobile): keep verified names on screen in channels with over 1,024 members (#9111)
  mobile: reuse channel message rows that did not change (#9115)
  fix(mobile): back off push bootstrap retries (#9092)
  fix(mobile): keep reply counts on screen while a reconnect catches up (#9100)
  fix(mobile): inflate gzip read-state snapshot responses (#9089)
  perf(relay): cache the community-active check on socket admission (#9109)
  fix(db): auto-migrate prebuild-guarded indexes on small databases (#8802)

Signed-off-by: Will Pfleger <wpfleger@block.xyz>

This branch was previously deployed

1 inactive deployment
codex-review — a481b5bb Deployed Nov 4, 2026 by TheSentinel454 via Run Codex Security Review #12677
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex-security-review-current The posted Codex security review matches its recorded range.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants