fix: share multisite transaction journals - #400
Merged
Merged
Conversation
chubes4
marked this pull request as ready for review
September 9, 2026 18:46
chubes4
added a commit
that referenced
this pull request
Sep 24, 2026
…434) wp_users is the one core table whose compiled column set differs between the single-site and multisite catalog variants (spam, deleted). WordPress promotes a single-site install to a network by running exactly this ALTER TABLE against it (dbDelta, inside populate_network()) -- one ADD COLUMN statement per missing column. A generated core table is described by the compiled schema catalog, not a persisted CREATE TABLE statement: creating one registers the catalog definition directly and never writes a `_schema/<suffix>.sql` file (see the core-table branch of WP_Markdown_Native_Schema_Mutation_Runtime::execute()). The ordinary ALTER path requires that persisted file to rewrite and recompile, so this ALTER TABLE failed closed as `unknown_table`, and reconcile_rows()'s existing backfill-on-ADD-COLUMN behavior -- already correct for a plugin's own persisted table -- never ran for a core table at all. Add execute_core_table_alter(): resolve the added column from the catalog's own two known variants, backfill it on the persisted snapshot via the existing reconcile_rows(), and rebuild the table's registration from the catalog so a core table's bespoke lookup semantics (e.g. wp_users' ASCII case-insensitive user_login matching) stay exactly what a fresh boot would build. MODIFY is a no-op (every shared column is identical between variants); DROP is intentionally unsupported and fails closed, since re-deriving from the catalog cannot shrink the compiled shape back down for a runtime whose is_multisite() state is fixed for its lifetime, and WordPress core has no DDL path that downgrades a core table this way. Investigation note, wp-codebox#2500: this ALTER TABLE gap is real and independently verified by the new smoke test, but it does not explain the issue's originally reported 15 mdi-native-only Route_AffinityTest failures on Extra-Chill/extrachill-api. Those do not reproduce against this repository's main (verified via wp-codebox's real PHPUnit harness with an explicit markdown-database-integration source pointed at an unmodified main checkout, both isolated -- 35/35 -- and full-suite -- 247/247). main already carries materialize_multisite_user_defaults() (WP_Markdown_Native_JSON_Snapshot_Provider::rows(), added in #393, merged 2026-09-10 19:00), an unconditional read-side default for wp_users rows missing the multisite-only columns, independent of whether any ALTER TABLE ever ran. wp-codebox's bundled mdi-native zip is pinned to 0bec3f7 ("share multisite transaction journals", #400, merged 2026-09-09 14:46) -- a day older than, and an ancestor of, #393. The bundled zip predates the fix; main already has it. Confirmed via isolation test that this ALTER TABLE fix, applied alone with materialize_multisite_user_defaults() neutralized, does not reproduce the fix either -- main's real bootstrap does not appear to reach this ALTER TABLE path for wp_users at all, so wp_insert_user() working correctly rests entirely on the read-side default. This fix stands on its own merit regardless: an ALTER TABLE WordPress core genuinely issues against a generated core table should not fail closed and silently skip reconciling existing rows. See the PR description for the full investigation writeup. Ref: Automattic/wp-codebox#2500
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Share native transaction ownership across multisite scopes and serialize canonical writes across processes before pre-image reads, ID allocation and narrower statement locks. Hold the root write lock through transaction completion; autocommit releases it after the statement.
Recover abandoned journals before admitting writes. Recovery, decode, cleanup and unsafe-path failures block further admission until safely retried. Only factory-configured canonical roots are admitted, including split state/content roots; cached owners receive validated later roots. Stable lock files reject symlinks, hardlinks and nonregular files.
Verification
Exact candidate
96887dd97e87eff5b22a1a4d5cafcf8d65bf269b.Parent independently ran the following on Linux at that exact Git head:
All passed, including independent-process post/option/JSON writes, crash recovery after a prior startup lock miss, failed-recovery retries, unsafe locks, split-root rename/delete rollback, abandoned split-root restoration, and multisite cross-scope post rollback. The pinned Codebox multisite install/switch and cold-reload acceptance also passed in worker verification.
Limits
This establishes write serialization, not MVCC or InnoDB read isolation. Contention has a five-second wait limit and may return an explicit failure. Runtime instances for the same root within one PHP process still share one logical transaction owner; independent same-process connection isolation is not provided. #377 remains open for broader SQL and consumer parity.
No release or deployment is included.
AI Assistance
GPT-5.6 Terra (
openai/gpt-5.6-terra) via OpenCode implemented the repair and regression coverage. GPT-6 Astra (openai/gpt-6-astra) via OpenCode reviewed lock ordering, recovery admission and split-root lifecycle, requested corrections, independently reran the exact Linux safety tests, and finalized evidence under Chris Huber's direction.