Skip to content

[Lint] "Fix broken link" writes type: query stubs into knowledge folders — the page is then invisible in the graph and dropped by schema routing on the next ingest #733

Description

@CuongGIK

bug, lint, knowledge-graph

Summary

When Wiki Lint fixes a broken wikilink by creating a placeholder, it keeps the directory of the broken target but hard-codes type: query. The result is a page such as wiki/concepts/clash-detection.md carrying type: query. Two things follow immediately:

  1. It is deleted from the knowledge graph. wiki-graph.ts removes every node whose type is query (HIDDEN_TYPES), so the page and all links pointing at it vanish from the graph.
  2. It violates the project's own schema. If schema.md declares a Page Types table, validateWikiPageRouting will drop that file on the next ingest ("Pages under wiki/concepts/ must use type concept"), i.e. the app later refuses content it created itself.

In my project this accumulated to 106 pages, and among them was the single most-referenced page in the entire wiki (160 inbound references) — completely invisible in the graph, which in turn made the Insights panel report a large number of isolated pages.

Where it comes from

src/lib/lint-fixes.ts:

export function stubRelativePathFromBrokenTarget(brokenTarget: string): string {
  const parts = normalized.split("/").map(makeQuerySlug).filter(Boolean)
  const rel = parts.length > 1 ? parts.join("/") : `queries/${parts[0] ?? "missing-page"}`
  return `${rel}.md`
}
const content = [
  "---",
  "type: query",            // <-- always query, regardless of destination folder
  `title: "${...}"`,
  ...
  "tags: [stub, lint]",

So a broken [[concepts/foo]] produces wiki/concepts/foo.md with type: query. Only single-segment targets land in wiki/queries/, where type: query would be correct.

Note the app already has the function needed to do this right — inferWikiTypeFromPath in src/lib/wiki-page-types.ts maps concepts → concept, standards → standard, etc. — but it is currently only used for UI labels.

Related second half: "Create Page" + sweep never agree

The same class of problem makes review suggestions repeat. src/lib/wiki-filename.ts always appends a timestamp:

fileName: `${slug}-${date}-${time}.md`   // e.g. attention-2026-09-06-143052.md

while sweepResolvedReviews resolves a missing-page item only on an exact name match (src/lib/sweep-reviews.ts, pageExistsindex.byId / index.byTitle). A page created from the suggestion therefore never matches the suggestion that produced it, and the item comes back on the next sweep.

I realise #495 already made review IDs content-stable so resolved state survives regeneration — this is the remaining gap: the page the user creates cannot be recognised, independently of how the ID is computed.

Environment / measurements

LLM Wiki v0.6.11, Windows 11, 2,933 markdown files.

  • 106 pages with type: query sitting in knowledge folders (concepts/ 55, entities/ 25, sources/ 9, playbooks/ 6, findings/ 5, standards/ 3, synthesis/ 2, comparisons/ 1), all created by Lint's "Fix".
  • After correcting their type to match the folder, those pages rejoined the graph and the isolated-page count dropped sharply.
  • 266 pages carried the -YYYY-MM-DD-HHMMSS suffix outside wiki/queries/, mostly from "Create Page".

Proposed fixes

  1. Derive the stub's type from its destination folder using the existing inferWikiTypeFromPath, falling back to query only for wiki/queries/. One line of intent, and it makes Lint's output consistent with the schema routing the app enforces elsewhere.
  2. Or always place stubs in wiki/queries/ regardless of the target's path, so type: query is truthful. (Less good: it loses the author's intended location, and the broken link still will not resolve unless the target was single-segment.)
  3. Do not append a timestamp when the slug is free. Use slug.md if it does not exist and only fall back to slug-YYYY-MM-DD-HHMMSS.md on collision. That alone would let pageExists recognise pages created from suggestions.
  4. Optionally, have pageExists strip a trailing -YYYY-MM-DD(-HHMMSS) before comparing, so existing wikis benefit without a migration.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions