v2: confidence scores on INFERRED edges, avg shown in report

This commit is contained in:
Safi
2026-04-06 16:06:31 +01:00
parent 7e3da961a9
commit dafe6c9f03
6 changed files with 229 additions and 5 deletions
+7
View File
@@ -195,11 +195,18 @@ LEGEND.forEach(c => {{
</script>"""
_CONFIDENCE_SCORE_DEFAULTS = {"EXTRACTED": 1.0, "INFERRED": 0.5, "AMBIGUOUS": 0.2}
def to_json(G: nx.Graph, communities: dict[int, list[str]], output_path: str) -> None:
node_community = _node_community_map(communities)
data = json_graph.node_link_data(G, edges="links")
for node in data["nodes"]:
node["community"] = node_community.get(node["id"])
for link in data["links"]:
if "confidence_score" not in link:
conf = link.get("confidence", "EXTRACTED")
link["confidence_score"] = _CONFIDENCE_SCORE_DEFAULTS.get(conf, 1.0)
with open(output_path, "w") as f:
json.dump(data, f, indent=2)
+13 -2
View File
@@ -24,6 +24,10 @@ def generate(
inf_pct = round(confidences.count("INFERRED") / total * 100)
amb_pct = round(confidences.count("AMBIGUOUS") / total * 100)
inf_edges = [(u, v, d) for u, v, d in G.edges(data=True) if d.get("confidence") == "INFERRED"]
inf_scores = [d.get("confidence_score", 0.5) for _, _, d in inf_edges]
inf_avg = round(sum(inf_scores) / len(inf_scores), 2) if inf_scores else None
lines = [
f"# Graph Report - {root} ({today})",
"",
@@ -41,7 +45,8 @@ def generate(
"",
"## Summary",
f"- {G.number_of_nodes()} nodes · {G.number_of_edges()} edges · {len(communities)} communities detected",
f"- Extraction: {ext_pct}% EXTRACTED · {inf_pct}% INFERRED · {amb_pct}% AMBIGUOUS",
f"- Extraction: {ext_pct}% EXTRACTED · {inf_pct}% INFERRED · {amb_pct}% AMBIGUOUS"
+ (f" · INFERRED: {len(inf_edges)} edges (avg confidence: {inf_avg})" if inf_avg is not None else ""),
f"- Token cost: {token_cost.get('input', 0):,} input · {token_cost.get('output', 0):,} output",
"",
"## God Nodes (most connected - your core abstractions)",
@@ -55,8 +60,14 @@ def generate(
relation = s.get("relation", "related_to")
note = s.get("note", "")
files = s.get("source_files", ["", ""])
conf = s.get("confidence", "EXTRACTED")
cscore = s.get("confidence_score")
if conf == "INFERRED" and cscore is not None:
conf_tag = f"INFERRED {cscore:.2f}"
else:
conf_tag = conf
lines += [
f"- `{s['source']}` --{relation}--> `{s['target']}` [{s['confidence']}]",
f"- `{s['source']}` --{relation}--> `{s['target']}` [{conf_tag}]",
f" {files[0]} → {files[1]}" + (f" _{note}_" if note else ""),
]
else:
+8 -1
View File
@@ -210,8 +210,15 @@ DEEP_MODE (if --mode deep was given): be aggressive with INFERRED edges - indire
If a file has YAML frontmatter (--- ... ---), copy source_url, captured_at, author,
contributor onto every node from that file.
confidence_score rules:
- EXTRACTED edges: confidence_score must be 1.0
- INFERRED edges: score 0.4-0.9 based on how certain you are.
Strong structural inference (e.g. two classes clearly share data): 0.8-0.9.
Reasonable but not certain: 0.6-0.7. Weak inference: 0.4-0.5.
- AMBIGUOUS edges: score 0.1-0.3
Output exactly this JSON (no other text):
{"nodes":[{"id":"filestem_entityname","label":"Human Readable Name","file_type":"code|document|paper|image","source_file":"relative/path","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","source_file":"relative/path","source_location":null,"weight":1.0}],"input_tokens":0,"output_tokens":0}
{"nodes":[{"id":"filestem_entityname","label":"Human Readable Name","file_type":"code|document|paper|image","source_file":"relative/path","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"relative/path","source_location":null,"weight":1.0}],"input_tokens":0,"output_tokens":0}
```
**Step B3 - Collect, cache, and merge**