feat(graph): warn on low citing-paper coverage in graph report (R-D)

Add graph.citing_coverage() (papers with >=1 out-edge / total) and a graph_min_citing_coverage setting (default 0.8). codex graph report now surfaces 'Citing coverage: N/M papers with out-edges (P%)' in text and JSON, and warns when the share is below threshold -- low citing coverage starves PageRank/coupling even when the paper count looks healthy (the DQ-1 sub-item). Separate from the existing total-count graph_min_corpus_size warning.

Tests: citing_coverage unit tests + CLI tests (line shown, warning fires/suppressed, JSON field). Full suite green; ruff + mypy clean. Live: graph report shows 29/29 (100%), no warning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-06-18 07:59:25 +02:00
parent 1516684bbb
commit 5672358bbe
6 changed files with 118 additions and 2 deletions

View File

@@ -538,7 +538,12 @@ def graph_report(
"""Show citation graph report: top hub papers, dangling citations, cluster summary."""
from codex.config import get_settings
from codex.db import get_conn
from codex.graph import build_citation_graph, citation_pagerank, dangling_citations
from codex.graph import (
build_citation_graph,
citation_pagerank,
citing_coverage,
dangling_citations,
)
settings = get_settings()
with get_conn() as conn:
@@ -553,6 +558,8 @@ def graph_report(
pr = citation_pagerank(graph)
hubs = sorted(pr.items(), key=lambda x: -x[1])[:top_n]
dangling = sorted(dangling_citations(graph, known_ids))
n_citing, _ = citing_coverage(graph, known_ids)
coverage = n_citing / n_papers if n_papers else 0.0
if output_json:
typer.echo(
@@ -560,6 +567,11 @@ def graph_report(
{
"nodes": graph.number_of_nodes(),
"edges": graph.number_of_edges(),
"citing_coverage": {
"citing": n_citing,
"papers": n_papers,
"fraction": round(coverage, 4),
},
"hubs": [{"paper_id": pid, "pagerank": score} for pid, score in hubs],
"dangling_count": len(dangling),
"dangling": dangling,
@@ -575,7 +587,17 @@ def graph_report(
f"(recommended ≥ {settings.graph_min_corpus_size} for meaningful ranking).",
err=True,
)
# R-D: low citing-paper coverage starves PageRank/coupling even at a healthy
# paper count — warn on the share of papers that actually have out-edges.
if coverage < settings.graph_min_citing_coverage:
typer.echo(
f"Warning: only {n_citing}/{n_papers} papers ({coverage:.0%}) have out-edges "
f"(recommended ≥ {settings.graph_min_citing_coverage:.0%}); "
f"low citing coverage weakens PageRank/coupling.",
err=True,
)
typer.echo(f"Graph: {graph.number_of_nodes()} nodes, {graph.number_of_edges()} edges")
typer.echo(f"Citing coverage: {n_citing}/{n_papers} papers with out-edges ({coverage:.0%})")
typer.echo("")
typer.echo(f"TOP-{top_n} HUB PAPERS (PageRank)")
typer.echo("-" * 48)