Skip to content

suggest_questions() isolated-node count (757) disagrees with report.py Knowledge Gaps count (245) — inflated by rationale/JSON-leaf/TS-Props nodes #1768

Description

@Riaan180390

Summary

suggest_questions()'s "isolated/weakly-connected nodes" question overcounts by ~3x compared to the report's own "Knowledge Gaps" section, because it's missing filters that report.py already applies. The inflated number makes a healthy graph look like it has a major documentation/connectivity problem when it doesn't.

Where

  • graphify/analyze.py, suggest_questions(), the "Isolated or weakly-connected nodes" block (~line 504):
    isolated = [
        n for n in G.nodes()
        if G.degree(n) <= 1 and not _is_file_node(G, n) and not _is_concept_node(G, n)
    ]
  • graphify/report.py's "Knowledge Gaps" section (~line 237) does the same computation but adds one more filter:
    isolated = [
        n for n in G.nodes()
        if G.degree(n) <= 1
        and not _is_file_node(G, n)
        and not _is_concept_node(G, n)
        and G.nodes[n].get("file_type") != "rationale"
    ]

Repro

On a 2213-node / 4862-edge real-world graph (Python + TS/React monorepo), the two computations disagree:

  • suggest_questions() count (no rationale exclusion): 757
  • report.py "Knowledge Gaps" count (with rationale exclusion): 245

Both appear in the same generated report (GRAPH_REPORT.md) — the Suggested Questions section says "757 weakly-connected nodes found — possible documentation gaps," while the Knowledge Gaps section a few paragraphs earlier says 245, for what's presented as the same concept. That's an internal inconsistency a reader will notice.

Root cause of the inflation

I broke down the 757 by file_type:

file_type count % is it a real gap?
rationale 512 68% No — these are auto-extracted docstring/comment nodes attached to their parent symbol by exactly one edge (e.g. a node whose label is the first line of a function's docstring). Degree=1 is the intended shape for these, not a missing edge.
code (JSON leaves) 86 11% No — scalar values in JSON config trees (e.g. shadcn's components.json: $schema, rsc, baseColor, cssVariables). Same "single parent edge by construction" pattern as _JSON_NOISE_LABELS already tries to filter for package.json, but that noise list doesn't cover other config schemas.
code (TS Props interfaces) ~130 17% No — single-use React/TypeScript prop-type interfaces declared immediately above the one component that uses them (FlowProps, TopBarProps, BottomPanelProps, etc.). Idiomatic single-use types, not undocumented code.
everything else ~29 4% plausible real gaps

So even the smaller, "already filtered" 245 count from report.py still isn't clean — it doesn't exclude JSON config leaves or single-use TS prop interfaces, both of which are structural/idiomatic patterns rather than architectural gaps.

Suggested fix

  1. Add the same file_type != "rationale" filter to suggest_questions()'s isolated-node computation so it doesn't disagree with report.py.
  2. Extend the JSON-leaf exclusion (currently _is_json_key_node + _JSON_NOISE_LABELS, scoped to package-manager-style keys) to catch degree-1 leaves in any JSON file — the label being a leaf value under a JSON source with degree ≤1 is a strong enough signal regardless of which specific JSON schema it is.
  3. Consider a heuristic for single-use TS/JS *Props/*Options/*Config interfaces (declared in the same file as, and only referenced by, one consumer) — these are idiomatic and shouldn't count toward "knowledge gaps" either.

Happy to share the exact reproduction script (loads graph.json, replicates both filters) if useful — got exact parity with both 757 and 245 by hand-rolling the same predicates.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions