fix(F-15): address Opus review findings (CRITICAL + WARN)
CRITICAL: - cli.py: invert cite-boost formula: divide distance by (1 + alpha*pr) instead of multiply — high-PageRank papers now correctly rank higher - cli.py: wire graph_min_corpus_size config into graph report; warning emitted to stderr so JSON stdout stays parseable WARN: - graph.py: document that damping is ignored in small-graph uniform branch - cli.py: sort dangling citations before slicing for stable output - cli.py: replace raise typer.Exit(0) with return in empty-graph path - tests: fix *extra_args helper signatures; add cite-boost ordering test and small-corpus warning test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
16
codex/cli.py
16
codex/cli.py
@@ -103,7 +103,8 @@ def search_paper(
|
||||
results = []
|
||||
for row in rows:
|
||||
pr_score = pr.get(row["id"], 0.0)
|
||||
boosted = row["distance"] * (1.0 + alpha * pr_score)
|
||||
# distance is lower=better; divide to reduce distance for high-PR papers
|
||||
boosted = row["distance"] / (1.0 + alpha * pr_score)
|
||||
results.append((boosted, row))
|
||||
results.sort(key=lambda x: x[0])
|
||||
for boosted_dist, row in results:
|
||||
@@ -535,20 +536,23 @@ def graph_report(
|
||||
output_json: bool = typer.Option(False, "--json", help="Output as JSON."),
|
||||
) -> None:
|
||||
"""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
|
||||
|
||||
settings = get_settings()
|
||||
with get_conn() as conn:
|
||||
graph = build_citation_graph(conn)
|
||||
known_ids = {row["id"] for row in conn.execute("SELECT id FROM papers").fetchall()}
|
||||
|
||||
if graph.number_of_nodes() == 0:
|
||||
typer.echo("Citation graph is empty — ingest some papers first.")
|
||||
raise typer.Exit(0)
|
||||
return
|
||||
|
||||
n_papers = len(known_ids)
|
||||
pr = citation_pagerank(graph)
|
||||
hubs = sorted(pr.items(), key=lambda x: -x[1])[:top_n]
|
||||
dangling = dangling_citations(graph, known_ids)
|
||||
dangling = sorted(dangling_citations(graph, known_ids))
|
||||
|
||||
if output_json:
|
||||
typer.echo(
|
||||
@@ -565,6 +569,12 @@ def graph_report(
|
||||
)
|
||||
return
|
||||
|
||||
if n_papers < settings.graph_min_corpus_size:
|
||||
typer.echo(
|
||||
f"Warning: only {n_papers} ingested papers "
|
||||
f"(recommended ≥ {settings.graph_min_corpus_size} for meaningful ranking).",
|
||||
err=True,
|
||||
)
|
||||
typer.echo(f"Graph: {graph.number_of_nodes()} nodes, {graph.number_of_edges()} edges")
|
||||
typer.echo("")
|
||||
typer.echo(f"TOP-{top_n} HUB PAPERS (PageRank)")
|
||||
|
||||
@@ -64,9 +64,13 @@ def citation_pagerank(graph: nx.DiGraph, *, damping: float = 0.85) -> dict[str,
|
||||
-------
|
||||
``{paper_id: score}`` dict. Scores sum to approximately 1.0.
|
||||
|
||||
When ``graph`` has fewer than :data:`_MIN_PAGERANK_NODES` nodes,
|
||||
returns a uniform distribution and logs a warning — the signal is
|
||||
too thin to be meaningful.
|
||||
When ``graph`` has fewer than :data:`_MIN_PAGERANK_NODES` (5) nodes,
|
||||
returns a uniform distribution and logs a warning — the graph is too
|
||||
sparse for the random-walk model to converge meaningfully. The
|
||||
``damping`` parameter is ignored in this branch. The user-facing
|
||||
corpus-size threshold (default 15) lives in
|
||||
:attr:`codex.config.Settings.graph_min_corpus_size` and is surfaced
|
||||
by ``codex graph report``.
|
||||
"""
|
||||
n = graph.number_of_nodes()
|
||||
if n == 0:
|
||||
|
||||
Reference in New Issue
Block a user