markfluence check-project: validate what only the whole project reveals
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 2
- Forks
- 0
- Avg merge
- 2h 8m
- Merged PRs (30d)
- 49
Description
A second, offline validator for the things that are only visible by looking at a project's whole set of declarations at once — which markfluence check cannot see by construction, since its diagnostics are deliberately per-file.
The hole, demonstrated
Two files declaring the same page_id and the same title+space, checked in one invocation:
$ markfluence check one.md two.md
[one.md] clean
[two.md] clean
markfluence update one.md two.md then publishes both to page 12345, the second silently overwriting the first. Nothing in markfluence catches this today, and check had both files in hand when it said "clean" — because a per-file check is the wrong shape for a relation between two files.
What it could check
Offline, in all cases. No credentials, no network — the property that makes check usable anywhere, and the reason anything needing the network belongs elsewhere (see "Out of scope").
Strong — real hazards with no current diagnostic:
- Two declarations claiming one
page_id. Silent mutual overwrite, as above. Applies to frontmatter, topages:entries (#139), and to one of each. - Two declarations claiming one
titlein onespace. Confluence enforces title uniqueness per space, so this is a guaranteed failure — and a partial one, since both files passcreate's preflight when neither title exists yet and the collision only surfaces once one page has been created. That is exactly the situation S7 (no-partial-create, status Partial) describes, so catching it offline would strengthen a guarantee rather than merely save a round trip. pages:entries naming no file on disk. #139's D12 makes this deliberately silent — legitimate for a deleted file or a sparse checkout, so not an error — and there is currently no way to ask.- Files under the root that neither location claims. "Which of my docs aren't published?" is unanswerable today:
updateskips them, correctly and silently (D7).
Medium:
- A
parentchain that dangles or cycles across the project, rather than within one invocation.createrejects a cycle among the files it is given (cmd/create/create.go,parent cycle detected among the given files), but a manifest can declare one that no single batch exercises — and aparentnaming a path with no metadata anywhere is only caught today if that file happens to be named.
Weak — I would leave these out unless someone asks: orphan pages nothing links to, unreferenced assets under the root, and an entry whose space differs from the project-wide space: (legal, not a defect).
Output should be diagnostics, not a tree
Considered and rejected: rendering the project as a page tree.
Two of the strongest checks are not tree-shaped at all — a duplicate page_id is a relation between two arbitrary nodes, which a tree can only annotate and hope the reader connects, where a line says it outright. The "tree" is also frequently degenerate: a project using parent: <id> for an external page or folder has a forest of roots, and one with no parent: anywhere is a flat list. And check's value is one line per problem plus an exit code; a validator that prints a picture stops being something you put in CI.
markfluence would also then have three tree printers — children for the live tree, #148's local one, and this — which is the "a per-command copy is how two commands come to disagree" problem in output form.
What should be shared is the graph, not the output. The local page graph (every declared page, its parent, whether that parent resolves) is what this needs to find dangles and cycles and what a tree view needs to draw. One internal package, two consumers — the same arrangement as internal/pagemeta and internal/linkindex, for the same reason. A --tree presentation on top of that is then cheap, if it turns out to be wanted.
Naming, and why the timing matters
This would be the second check-* verb, which is the condition that makes renaming check → check-file worth doing: a compound name earns its length when there is something to disambiguate from, and not before. Compound names are already house style here (attachment-list/attachment-upload/attachment-download, noun-first so cobra's alphabetized help groups them).
Worth noting the timing: renaming check touches the --json schema's command enum and checkResult, which is a published contract. markfluence is unreleased, so that is free today and a breaking change after 1.0.0 — so if this lands post-1.0, the rename option has effectively expired and check keeps its name. No milestone set; flagging the constraint rather than deciding it.
Out of scope
Anything requiring the network, which keeps this offline and credential-free:
- Entries whose
page_idresolves to nothing. Needs a request per page. - Drift between a file and its live page. #148, and possibly a
markfluence diff— see that issue.
Related
- #139 —
pages:entries. D12 and D7 are where two of these blind spots come from, deliberately. - #148 —
markfluence status/markfluence diff. The tree-view and drift wants live there; this issue is the offline, set-relation half, and the two should share the page graph rather than each build one. - #151 — removing
markfluence fix. Unrelated except that both are part of working out what markfluence's verbs should be. - docs/guarantees.md — S7 (
no-partial-create, Partial) is what check 2 would support.
Contributor guide
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 with the existing markfluence check command and read cmd/create/create.go for the current parent-cycle behavior. Review internal/pagemeta and internal/linkindex to understand the shared graph direction described here. Done means an offline validator reports the specified project-wide collisions, unresolved local references, and unclaimed files without requiring credentials or network access.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- cli
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100