Skip to content

markfluence check-project: validate what only the whole project reveals #152

Description

@willkg

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:

  1. Two declarations claiming one page_id. Silent mutual overwrite, as above. Applies to frontmatter, to pages: entries (markfluence.yaml pages: page metadata outside the markdown file #139), and to one of each.
  2. Two declarations claiming one title in one space. Confluence enforces title uniqueness per space, so this is a guaranteed failure — and a partial one, since both files pass create'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.
  3. pages: entries naming no file on disk. markfluence.yaml pages: page metadata outside the markdown file #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.
  4. Files under the root that neither location claims. "Which of my docs aren't published?" is unanswerable today: update skips them, correctly and silently (D7).

Medium:

  1. A parent chain that dangles or cycles across the project, rather than within one invocation. create rejects 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 a parent naming 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 checkcheck-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:

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions