Skip to content

feat(update): move a page to its declared parent, refuse another space - #202

Merged
willkg merged 3 commits into
mainfrom
update-moves-pages
Sep 25, 2026
Merged

willkg merged 3 commits into
mainfrom
update-moves-pages

Conversation

@willkg

@willkg willkg commented Sep 25, 2026

Copy link
Copy Markdown
Member

Fixes #10. update published the body, title, width, labels and status but ignored space and parent, which left the two coordinates outside L9. Plan: _plans/053_update-moves-pages.md (amended with what implementation and review changed).

Upgrade note: update now moves pages. Every file create wrote carries a parent: line (an id, or null for a top-level page). So the first update after upgrading moves any page that someone moved by hand in Confluence back to the parent its file records, subtree included. That is L9 working as written, and it is how labels already behave, but it is a quiet change for anyone who rearranged a tree in the UI. Run update --dry-run (or diff) first to see which pages would move, and edit parent: in those files to keep the new places. This belongs in the release notes.

Parent.

  • An id or a .md path moves the page under that page or folder.
  • parent: null (or ~, or an empty value) moves it to the top of the space.
  • An absent parent leaves the page where it is.
  • A moved page goes last among its new siblings. markfluence does not manage sibling order; reordering is done in Confluence.
  • Every move uses the v1 move route. It leaves the page version alone, where a v2 parentId change bumps it, so a move stays out of the moved-page check and the unchanged-body skip. v1 is also the only route that reaches the top of a space: v2 silently ignores a null parentId. The measurements are in docs/confluence/api.md.

Checks before any write. Every read the move needs happens first, so --dry-run reports a move that would fail. The parent must resolve, be a number or a .md path, be a page or folder in the page's space, and not be the page itself or below it. The loop check walks the target's parentId chain, since v2's ancestors route needs a scope nothing else here needs. The move is the first write, and a failed move fails the file.

Space. A space is a refusal, never a move. A page outside the file's space, or outside markfluence.yaml's space: default when the file names none, fails with nothing written. Keys compare without regard to case, which is how Confluence resolves them.

Frontmatter against pages: entry. A blank parent is now a value when the two locations are compared, so parent: null in one against an id in the other is a coordinate disagreement and fails the file.

Output.

Also:

  • diff compares parent: null and the project's space default, to match.
  • The ".md parent → page id" code that create and diff each had is now internal/parentref, which update uses too.
  • pagemeta.Resolved gained Space(root) and Parent().

Verified end to end against a personal space with the built binary:

  • a matching parent skipped the file;
  • a dry run previewed a move and wrote nothing;
  • moving under a page, to the top, and back under a .md parent each left the page at the same version with the body PUT skipped;
  • a loop was refused;
  • a space declared in the file, and one from the project default, were each refused;
  • diff reported the project-default space.

Plan for #10: update refuses a page in another space and moves a page
to its declared parent.
update published the body, title, width, labels and status but ignored
space and parent, which left the two coordinates outside L9.

A declared parent is now asserted by moving the page: an id or a .md
path moves it under that page or folder, parent: null (or ~, or an empty
value) moves it to the top of the space, and an absent parent leaves it
alone. A moved page goes last among its new siblings; markfluence does
not manage sibling order. Every move uses the v1 move route, which
leaves the page version alone where a v2 parentId change bumps it, so a
move stays out of the moved-page check and the unchanged-body skip, and
v1 is the only route that reaches the top of a space.

Every read the move needs happens before any write, so --dry-run reports
a move that would fail: the parent resolves, is a page or folder in the
page's space, and is not the page itself or below it. The loop check
walks the target's parentId chain, since v2's ancestors route needs a
scope nothing else here needs. The move is the first write, and a
failed move fails the file.

A space is a refusal, never a move: a page outside the file's space, or
outside markfluence.yaml's space: default when the file names none,
fails before any write.

--json gains moved on update results, null or {from, to}; a new key is
compatible since #200. diff compares parent: null and the project
default space, to match. The ".md parent -> page id" code create and
diff each had is now internal/parentref, which update uses too.

Fixes #10.
- moved is set only once the move has happened (or under --dry-run), so
  a failure after planning no longer claims a move; a move made before a
  later failure is reported in human output too.
- A blank parent is a value when frontmatter and a pages: entry are
  compared, so parent: null against an id is a coordinate disagreement
  instead of the id winning silently.
- A parent that is neither digits nor a .md path is refused before any
  request, and so is a .md parent whose page_id is not a number.
- The already-in-place check also compares the id the server returned,
  so 0100 does not move a page onto its own parent; the move targets
  that id.
- Space keys compare without regard to case, which is how Confluence
  resolves them (measured: sre, Sre and SRE all name SRE). A page whose
  space cannot be told is refused with that reason, and a move to the
  top of the space refuses rather than requesting a malformed route.
- Among top-level pages sharing a position, the last one listed is last.
- Within's comment says what an unreadable ancestor costs: only the
  preview, since Confluence still refuses a real loop.
@willkg
willkg merged commit 70bb4af into main Sep 25, 2026
1 check passed
@willkg
willkg deleted the update-moves-pages branch September 25, 2026 16:04
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.

update: enforce space/parent and support page moves

1 participant