Skip to content

[BUG] EDGE_TYPE_ALIASES maps documented_by to documents without swapping endpoints, silently reversing the edge #653

Description

@fabio-rovai

Summary

EDGE_TYPE_ALIASES maps documented_by to documents, and normalizeGraph rewrites the edge type without swapping source and target:

return { ...edge, type: edgeAliases[edge.type] };

documented_by and documents are converses, so the rewrite silently reverses the edge. This is the same hazard the table already documents for a different alias:

// Note: "implemented_by" is intentionally NOT aliased to "implements" —
// it inverts edge direction (see commit fd0df15). The LLM should use
// "implements" with correct source/target instead.

The rule is right; documented_by slipped past it.

Version

main at b77e3e8c, @understand-anything/core 0.1.0, built with pnpm build, Node 26.

Reproduction

import { normalizeGraph } from "./dist/schema.js";

const graph = {
  kind: "codebase",
  nodes: [
    { id: "auth.ts", name: "auth.ts", type: "file" },
    { id: "auth.md", name: "auth.md", type: "document" },
    { id: "handler.ts", name: "handler.ts", type: "file" },
    { id: "queue", name: "queue", type: "service" },
  ],
  edges: [
    { source: "auth.ts", target: "auth.md", type: "documented_by" },
    { source: "handler.ts", target: "queue", type: "triggers_on" },
    { source: "auth.ts", target: "auth.md", type: "implemented_by" },  // control
  ],
};

for (const e of normalizeGraph(graph).edges) {
  console.log(`${e.source} --${e.type}--> ${e.target}`);
}

Actual

auth.ts --documents--> auth.md
handler.ts --triggers--> queue
auth.ts --implemented_by--> auth.md

The first edge said auth.ts is documented by auth.md. After normalisation it says auth.ts documents auth.md, so the source file now documents its own documentation. The third line is the control: implemented_by is left alone exactly as the comment describes, which shows the safeguard works and this case was simply missed.

Why it is hard to notice downstream

Nothing errors, no issue is recorded in autoFixGraph, and the edge count is unchanged. The graph stays schema-valid because documents is a canonical type. Only the arrow is backwards, so any view answering "what documents this file", or any traversal that follows documents in one direction, returns the opposite of the truth for these edges. A reader has no way to tell an inverted edge from a correct one by looking at the output.

A second one I am less sure about

triggers_on maps to triggers in the same table, and the reproduction above shows handler.ts --triggers--> queue. If triggers_on is meant as "this handler fires in response to that queue", it is inverted for the same reason. If it is meant as "this triggers on that target", it is fine. I could not tell which reading you intend from the surrounding code, so I am raising it as a question rather than asserting it is wrong.

Not filed as a bug, but noticed while reading

Several node aliases are lossy in a way that may be deliberate: interface and struct both collapse to class, and migration, database and view all collapse to table. That is a modelling decision rather than a defect, so I have not filed it, but a knowledge graph that cannot distinguish a view from a table will answer some questions confidently and wrongly, and it seemed worth mentioning while I was in here.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions