Skip to content

Preserve Pages when trashing database collections - #4605

Draft
3mdistal wants to merge 3 commits into
mainfrom
codex/content-deletion-semantics
Draft

Preserve Pages when trashing database collections#4605
3mdistal wants to merge 3 commits into
mainfrom
codex/content-deletion-semantics

Conversation

@3mdistal

@3mdistal 3mdistal commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Problem

A Content Page can belong to several Databases. Moving one Database to Trash previously followed membership edges and trashed its member Pages, including Pages used elsewhere. Row menus also lacked a clear canonical Page Trash command alongside membership removal.

Change

Trash now follows Page hierarchy, locks and rechecks the affected resources and permissions in its transaction, and preserves membership-only Pages. New rows keep their own hierarchy position instead of inheriting the Database as their parent. Creation and moves coordinate with Trash so a live child cannot arrive under a trashed parent.

Table, List, Gallery and selection controls expose explicit Page Trash separately from membership removal. Batch results distinguish successful, already-trashed, ancestor-covered and failed requests. Confirmation freezes the selected Pages; Undo restores only roots actually changed. Success counts include affected descendants. Dialogs restore keyboard focus and use localized labels in all configured locales. Reference blocks say Remove reference and retain editor-local removal; View deletion remains a presentation operation. Favorites preview uses an explicit unpin mutation.

Legacy Database-parent edges do not record whether they originally meant membership or deliberate hierarchy. They return DATABASE_CHILD_OWNERSHIP_AMBIGUOUS before any mutation. This accepted limitation does not infer ownership or migrate old rows. Ordinary Page hierarchy remains supported.

Verification

Current pushed implementation has 129 passing lifecycle/row/source/form action tests, 45 focused parent/move assertions, 16 UI tests, and 13 toolkit tests. Content TypeScript check and toolkit build pass. An independent bounded review found and then verified repairs for post-commit false failures, concurrent child writes, and sibling-position races.

Real local browser checks cover row Trash/Undo, membership removal with the same Page URL, selected parent/child recovery, separate List/View operations, keyboard focus, and dialog bounds at 390, 768 and 1280 pixels. A Page owned by another local fixture identity and explicitly shared as viewer exposes no Trash command. A legacy ambiguity fixture reports its reason and remains live. Reference removal was exercised on a real unresolved Reference atom; SQL Page reference navigation is not supported by that renderer and is not claimed here.

Additional verification and integration

Human QA caught an additional read-side bug after Database A was trashed: the surviving member remains visible in B, but direct reads and Files still infer deletion from the deleted membership. The shared read filters are repaired: the same browser fixture now preserves direct URL/body/sidebar access while A is trashed, and restoring A restores its membership. Canonically trashed Pages still reject property reads. Final bulk Undo restores both selected parent and child and reports two affected Pages. Two ordinary memberships were seeded in the authorized local fixture harness because adding an existing Page to a second ordinary Database has no public Action/UI; this setup does not claim that creation capability.

The Windows aggregate guard runner fails with spawn EINVAL before execution. Eight relevant individually invoked guards pass. Localization catalogs report 2,537 existing repository issues; product docs report 1,002 issues; untracked-import checks produce verified Windows path-separator false positives. Changed-copy reports zero recognized surfaces and is not counted as localization coverage. The unscoped-query guard likewise inspected no tables. No baseline suppressions were added.

This draft is one part of the coordinated deletion work. Full read-only Trash behavior and viewer unpin belong to the adjacent lifecycle change; restore/purge controls and attribution belong to the recovery change. Duplicate ownership belongs to the sidebar change. Integration must retain their final shared helper and recovery hunks. No merge or deployment is requested.

Final read-boundary lifecycle suite: 46 passed; parity: 51 passed; CI recovery UI/move/Slack suites: 26 passed. Final Content typecheck passed. PostgreSQL locking fixtures now distinguish hierarchy from membership; real PostgreSQL and Linux security verification will run in CI. No local PostgreSQL service was available.

Follow-up PostgreSQL CI ran 15 tests: 14 passed; the restore-wins fixture hit the live-member preflight before exercising its race. Commit 057638a removes that fixture membership and requires both lock waiters before releasing the gate. The original restored-root rejection assertion is retained. Typecheck and formatting pass; CI run 34379663038 is pending for this test-only correction.

@netlify

This comment has been minimized.

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