fix: wp_posts partitioned sync preserves markdown-type rows (closes #66)#67
Merged
Conversation
Same partition hazard as #64/#65, now affecting wp_posts itself. persist_non_markdown_posts() regenerates _tables/posts.json whenever any non-markdown post type is created or updated. WordPress auto-creates a revision on every wp_update_post() call, so this fires on essentially every edit across the site. When sync_json_tables() saw posts.json's mtime change on the next warm boot, it truncated wp_posts and reloaded from JSON — wiping every markdown-type post row until the following request's heal_orphaned_ index_entries() could re-insert them from _markdown_file_index + disk. A full request window during which wp_count_posts(), WP_Query, and every REST endpoint returned zero markdown-type posts. Fix: add sync_posts_partition_from_json() that deletes only rows whose post_type is in the excluded (non-markdown) list, then reloads JSON. Markdown-type rows sourced from frontmatter survive the sync. Extracts the IN-clause quoting into quote_excluded_types_for_in_clause() so sync_partitioned_table_from_json() and sync_posts_partition_from_json() share the escaping path. Adds 22 pure-PHP smoke tests in tests/smoke-sync-posts-partition.php covering the happy path, empty excluded-types list, exact (non-prefix) post_type matching, SQL-injection-safe quoting, helper shape, and the live repro from issue #66 (141 wiki rows survive warm boot after a posts.json rewrite).
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
Closes #66. Same partition hazard as #64/#65, now affecting
wp_postsitself.persist_non_markdown_posts()regenerates_tables/posts.jsonwhenever any non-markdown post type is created or updated. Since WordPress auto-creates a revision on everywp_update_post()call, this fires on essentially every edit across the site — admin UI, Gutenberg, cron, CLI, REST.sync_json_tables()then sawposts.json's mtime change on the next warm boot, truncatedwp_posts, and reloaded the JSON — wiping every markdown-type post row until the following request'sheal_orphaned_index_entries()could re-insert them from_markdown_file_index+ disk.That's a full request window during which
wp_count_posts(),WP_Query, and every REST endpoint returned zero markdown-type posts. Briefings, scheduled flows, webhooks, and external API consumers all silently received empty data.Live repro on intelligence-chubes4 (primary mode)
Before this PR:
After this PR:
Fix
New private helper
sync_posts_partition_from_json()runs a surgicalDELETE FROM wp_posts WHERE post_type IN (excluded_types)before the JSON reload, leaving markdown-type rows untouched.sync_json_tables()dispatches to it when the changed file isposts.json.The IN-clause quoting path is extracted into
quote_excluded_types_for_in_clause()and shared betweensync_partitioned_table_from_json()(#65) and the newsync_posts_partition_from_json().Why this wasn't caught by #64/#65's fix
The #65 helper filters rows by looking up
post_idinwp_posts.post_type— that works forpostmeta/term_relationshipswhere thepost_typeis one join away. Forwp_postsitself the filter is onwp_posts.post_typedirectly, so it needs its own helper. Otherwise the shape is identical.Tests
tests/smoke-sync-posts-partition.php— 22 new pure-PHP smokes:revision_draftis NOT deleted whenrevisionis excludedquote_excluded_types_for_in_clause()helper shape including SQL-standard''escape for embedded single quotesposts.jsonrewritesmoke-inject-id.php— 23 ✓,smoke-search.php— 20 ✓,smoke-sync-partitioned.php— 12 ✓).Remaining work
Bug B (parent-promotion
_markdown_file_indexstaleness) is independent and will follow in a separate PR.