Copy/paste silently drops child blocks; originals left behind with block/page ≠ parent's block/page (undetected by graph validator)
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 28
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
## Copy/paste silently drops child blocks; originals left behind with mismatched `:block/page`
**Summary**
Copying a block subtree (a "Draft" outline with ~24 top-level Q&A blocks, several nested one level deep) from one page to a newly created page dropped the answer content for 5 of the 24 top-level items. The parent question blocks were copied correctly; their child (answer) blocks were not carried over, and no error or warning was surfaced during the paste.
**What we found, verified via raw DataScript query (not the app UI)**
- Source subtree: a "Draft" block on the `Publish` page (this block itself appears to be a stray leftover — see below) with 24 child blocks (questions), each with 1–3 further children (answers).
- Destination subtree: a "Draft" block correctly created on the new page (`To Those I May Serve`), also with 24 matching top-level question blocks.
- Diffing children counts per matching question block (by title, source vs destination) turned up 5 question blocks on the destination side with **zero** children, where the corresponding source block had 1–3:
- "Introduction" — source 1 child, destination 0
- "Where do I start?" — source 1 child, destination 0
- "Are you selling me something?" — source 1 child, destination 0
- "What is it like working with you?" — source 3 children, destination 0
- "How do I know if this is for me?" — source 2 children, destination 0
- The 19 other question blocks copied correctly with all children intact.
- The "lost" answer blocks were not actually deleted — they still exist in the graph, still `:block/parent`-linked to their original (source-side) question block. But their own `:block/page` reference points to a *different* page (`Purpose of Two Stewards`) than their parent's `:block/page` (`Publish`) — i.e., the child block's page-tag and its parent's page-tag disagree. This mismatch is the likely reason these children didn't get picked up by the copy operation, and also the reason they don't show up under normal tree-reads of the parent (via API tooling that reads by page) even though the raw `:block/parent` link is intact.
**Reproduction conditions (best guess, not fully isolated)**
This happened during a manual cut/paste in the desktop app of a deeply nested outline (multiple heading levels, some collapsed blocks) from one page to a brand-new page, as part of restructuring a large document into smaller constituent pages. We don't have exact repro steps for triggering the page-tag mismatch itself — flagging with what we have rather than withholding until we can isolate a minimal repro.
**Why this matters**
The paste operation gave no indication that any content had failed to transfer — the new page looked structurally complete (same 24 question headings). The only way we caught the loss was diffing child counts programmatically. A user relying on the UI alone would not notice missing content until much later, if ever.
**Logseq's own validator does not catch this**
Running Logseq's built-in graph validation over this same graph, after the bug had already occurred, reports full success:
```
Your graph is valid! {:entities 3393, :pages 398, :blocks 2969, :classes 42, :properties 169, :property-pairs 6175, :objects 365, :datoms 36391}
```
That check appears to only confirm that required attributes are *present* on each block (title, parent, order, page, uuid, timestamps) — not that a child's `:block/page` agrees with its parent's `:block/page`. A present-but-wrong page reference is schema-valid and referentially broken at the same time, so this whole class of corruption is invisible to the validator a user would actually run.
**It's broader than the one page we started with**
We built a small external tool to sweep pages for exactly this invariant (child `:block/page` must match parent's `:block/page`, walked via the non-corrupted `:block/parent` chain rather than the possibly-drifted `:block/page` field). Running it over the `Publish` page in this same graph turned up **14 blocks** with this exact mismatch — not just the 5 we'd found by hand. 9 of them belong to content we hadn't even identified as affected yet (blocks titled "The Thesis," "Fit Criteria," "The Professional Landscape," "The Anomalous Quality," "Two Stewards as Environment," "Drafts (in latest-first order)," "More random blocks," a file-path block, and an unresolved raw-UUID link block) — all still parented correctly, all mistagged with a page other than their parent's.
Sample findings (id = `:db/id`):
```
block_id 5773 "The Thesis" — page=2953 (Purpose of Two Stewards), parent 5813's page=2600 (Publish)
block_id 5855 "Fit Criteria" — page=2953, parent 5813's page=2600
block_id 5840 "The Professional Landscape" — page=2953, parent 5813's page=2600
block_id 5851 "Drafts (in latest-first order)" — page=2953, parent 5798's page=2600
block_id 5868 "More random blocks" — page=2953, parent 5798's page=2600
```
This suggests the drift isn't limited to one unlucky paste — it's accumulated across multiple operations on this graph over time, all with the same signature.
**Ask**
- Should copy/paste (and whatever else can produce this) refuse to proceed, or warn, when a to-be-moved child block's `:block/page` won't match its new parent's page context?
- Is there a known code path where a block's own `:block/page` can drift out of sync with its `:block/parent` chain — during copy/paste of collapsed or deeply nested blocks, or otherwise?
- Should the built-in graph validator check this invariant? Right now it validates attribute presence per block but not parent/child page agreement, so this entire failure mode passes silently.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the desktop app cut/paste case with nested or collapsed blocks, then inspect the built-in graph validation run and the raw DataScript queries described in the issue. Trace where child :block/page values are assigned during the operation. Done means the failure is reproducible and the affected operation or validator reports or prevents parent/child page mismatches.
Written by the indexing model from the issue text.
Assessment
- Domain
- database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100