diff --git a/docs/merge-reliability.md b/docs/merge-reliability.md index 12fa3378..8226d5db 100644 --- a/docs/merge-reliability.md +++ b/docs/merge-reliability.md @@ -23,7 +23,7 @@ when there is a test or document that exercises the specific merge invariant. | 4. Filesystem merge hardening | `tests/cow/filesystem.php` is a focused fast gate for safe source text/binary file application, unsafe absolute symlinks staying as auditable file conflicts, and directory/file type replacements staying review-held until an explicit audited source resolution applies them. `tests/cow/media_validator.php` fast-gates discovered upload validators for incomplete generated-size metadata, missing original upload files, and `_wp_attached_file` versus `_wp_attachment_metadata['file']` drift. `tests/cow/merge.php` covers file adds/deletes/conflicts, binary hash comparisons, symlink safety, directory/file and file/directory replacement review, rollback artifacts, upload-file validators, generated attachment file checks, original/generated dimension drift, generated-size filename drift, featured-image/image-block/media metadata drift, and unsafe metadata paths. `tests/cow/e2e.sh` verifies real merged upload originals and generated thumbnails. | Add stricter uploads-specific validators for more drift shapes and explicit attachment-regeneration decisions. | | 5. Crash consistency across DB/files/metadata/Git | `docs/merge-crash-consistency.md` lists the covered boundaries. `tests/cow/merge.php` covers target DB, metadata, file, rollback-failure, ID-band, and whole-branch rollback paths. `tests/cow/e2e.sh` drives public merge/create/reset/recover crash/retry flows for DB, metadata, before-file, after-file, recovery-cleanup, branch-birth, branch-reset publication failpoints, and actual smart-HTTP Git-created branch pushes interrupted before branch-birth metadata, before branch-list publication, and after branch-list publication, each verified after a fresh server restart. `tests/cow/git_server.php` covers Git-created branch birth, Git update/delete, stale cleanup, and object-prune interruption. | Broaden external kill harness coverage across the remaining Git-push failpoints and platform-specific APFS/cleanup checkpoints, then verify post-crash state from a fresh process. | | 6. Branch birth always captures merge bases | `crates/forkpress-storage/src/lib.rs` requires branch birth metadata for branch reuse/merge and blocks pending reset states. `tests/cow/git_server.php` covers Git-created branch DB/file base, ID-band, row identity, and cleanup/rollback paths. `tests/cow/e2e.sh` covers public create retry after interrupted birth metadata, public reset retry after interrupted reset publication, and remote-cache branch creation followed by AUTOINCREMENT-band insertion and mergeback to `main`. | Keep every new creation/reuse/reset path under the same invariant and add regressions whenever a new branch publication path is introduced. | -| 7. ID-band enforcement beyond happy paths | `tests/cow/id_bands.php` is a focused fast gate for separate branch AUTOINCREMENT bands, JSON/serialized references that keep branch IDs distinct without rewrite, and review-held non-AUTOINCREMENT `INTEGER PRIMARY KEY` plugin collisions. `tests/cow/merge.php` covers AUTOINCREMENT allocation, rollback, reset below old bands, independent branch IDs, explicit out-of-band source IDs, child rows behind held explicit post/term/user IDs, inserted and updated scalar/serialized/theme/widget `wp_options`, `wp_posts`, `wp_postmeta`, `wp_comments`, `wp_commentmeta`, `wp_usermeta`, `wp_termmeta`, `wp_term_taxonomy`, `wp_term_relationships`, post-author, taxonomy menu-item, reusable/media/avatar/navigation/query block `post_content`, and comment-user references behind held explicit post/term/user IDs, JSON/serialized references that keep branch IDs distinct, plugin validator review for no-FK child rows behind held explicit plugin AUTOINCREMENT parents, and non-AUTOINCREMENT `INTEGER PRIMARY KEY` plugin graph collisions as review-held. `tests/cow/e2e.sh` verifies runtime branch post IDs fall inside branch bands and requires an independently banded source/target WordPress post merge to finish with `status: completed` and zero recorded conflicts while preserving embedded JSON/serialized post IDs. | Expand explicit-ID/import handling beyond currently covered AUTOINCREMENT row-insert/rewrite cases and enforce review for more plugin/custom logical identities that are not safely bandable. | +| 7. ID-band enforcement beyond happy paths | `tests/cow/id_bands.php` is a focused fast gate for separate branch AUTOINCREMENT bands, JSON/serialized references that keep branch IDs distinct without rewrite, reset/reuse protection that allocates fresh bands when a branch DB drops below its old reservation, and review-held non-AUTOINCREMENT `INTEGER PRIMARY KEY` plugin collisions. `tests/cow/merge.php` covers AUTOINCREMENT allocation, rollback, reset below old bands, independent branch IDs, explicit out-of-band source IDs, child rows behind held explicit post/term/user IDs, inserted and updated scalar/serialized/theme/widget `wp_options`, `wp_posts`, `wp_postmeta`, `wp_comments`, `wp_commentmeta`, `wp_usermeta`, `wp_termmeta`, `wp_term_taxonomy`, `wp_term_relationships`, post-author, taxonomy menu-item, reusable/media/avatar/navigation/query block `post_content`, and comment-user references behind held explicit post/term/user IDs, JSON/serialized references that keep branch IDs distinct, plugin validator review for no-FK child rows behind held explicit plugin AUTOINCREMENT parents, and non-AUTOINCREMENT `INTEGER PRIMARY KEY` plugin graph collisions as review-held. `tests/cow/e2e.sh` verifies runtime branch post IDs fall inside branch bands and requires an independently banded source/target WordPress post merge to finish with `status: completed` and zero recorded conflicts while preserving embedded JSON/serialized post IDs. | Expand explicit-ID/import handling beyond currently covered AUTOINCREMENT row-insert/rewrite cases and enforce review for more plugin/custom logical identities that are not safely bandable. | | 8. Better stale-audit workflow | `docs/stale-audit-workflow.md` describes the revalidation model. `scripts/cow/merge.php` implements `revalidate-reviews`, `merge-audit --revalidate`, `merge-resolve --after-revalidate`, revalidation classes, source/target drift checks, plugin validator replacement evidence, and plugin replacement conflict links. `tests/cow/stale_audit.php` is a focused fast gate for reviewed cell conflicts, target drift detection, source cell/row drift detection, `needs-action` carry-forward, idempotent revalidation, audit-visible revalidation classes, and guarded `--after-revalidate` source resolution. `tests/cow/merge.php` covers stale row/cell/file drift, source drift, deleted targets, no-PK rowid replacement, supported WordPress semantic fingerprints, guarded resolution, idempotent carried notes, plugin validator rerun evidence through direct and `merge-audit --revalidate` paths, duplicate identical validator rerun handling, and replacement validator conflict ids. | Add broader plugin/schema source-drift evidence, more custom logical-identity classifiers, and guarded plugin/schema-specific resolution flows where appropriate. | | 9. Release gate issue | `scripts/build-dist.sh` and release preflight tests fail earlier when static-PHP prerequisites are missing, avoid macOS bash empty-array expansion under `set -u` while wrapping Apple Silicon `spc` commands in `arch -arm64`, and `docs/merge-reliability.md` tracks aarch64 macOS as a release gate. Trunk CI run `25952935740` passed `Build production dist bundle` and release-built COW APFS sparsebundle E2E on `aarch64-apple-darwin` and `x86_64-apple-darwin`, plus Linux COW E2E and Windows checks. The mac APFS e2e now tolerates only the known transient `hdiutil compact` "Resource temporarily unavailable" failure after storage has already detached. | Keep aarch64 macOS release and APFS sparsebundle E2E green on trunk before treating Mac artifacts as trustworthy; do not treat a transient compact skip as proof that compaction itself succeeded. | @@ -112,8 +112,9 @@ For branch-birth metadata validation without the Git publication harness, run: make test-cow-branch-birth ``` -For ID-band allocation, JSON/serialized branch ID preservation, and -non-bandable `INTEGER PRIMARY KEY` plugin collision checks, run: +For ID-band allocation, branch-reset reuse protection, JSON/serialized branch +ID preservation, and non-bandable `INTEGER PRIMARY KEY` plugin collision +checks, run: ```bash make test-cow-id-bands diff --git a/tests/cow/id_bands.php b/tests/cow/id_bands.php index 4b1cd05b..1679b96a 100644 --- a/tests/cow/id_bands.php +++ b/tests/cow/id_bands.php @@ -150,6 +150,25 @@ function create_id_band_db(string $path): void { 1, 'plain INTEGER PRIMARY KEY plugin collision is recorded as a review conflict' ); + + $reset = $tmp . '/reset.sqlite'; + copy($base, $reset); + $reset_band = cow_merge_allocate_autoincrement_bands($reset, $metadata, 'feature-source'); + assert_same($reset_band['allocated'], 2, 'reset branch DB below its old band gets fresh AUTOINCREMENT bands'); + assert_same($reset_band['reused'], 0, 'reset branch DB below its old band does not reuse possibly published bands'); + assert_true( + (int)scalar($reset, "SELECT seq FROM sqlite_sequence WHERE name = 'wp_posts'") > $target_post_id, + 'fresh reset post band is above previously allocated branch post IDs' + ); + assert_true( + (int)scalar($reset, "SELECT seq FROM sqlite_sequence WHERE name = 'wp_options'") >= (int)scalar($metadata, "SELECT band_start - 1 FROM merge_autoincrement_bands WHERE branch_name = 'feature-source' AND table_name = 'wp_options'"), + 'fresh reset option band is recorded in the app DB sequence' + ); + assert_same( + (int)scalar($metadata, "SELECT COUNT(*) FROM merge_runs WHERE source_branch = 'feature-source' AND policy = 'autoincrement-id-band-allocation' AND status = 'id_bands_allocated'"), + 2, + 'reset-safe AUTOINCREMENT allocation runs are auditable' + ); } finally { remove_tree($tmp); }