/** * GRAPH_REPORT.md generator * * Produces a human-readable audit report from the knowledge graph: * - Corpus summary * - God nodes (most-connected entities) * - Community overview * - Surprising connections * - Suggested questions */ import type { KnowledgeGraph } from "./graph.ts"; import type { GraphStats } from "./types.ts"; interface Surprise { source: string; target: string; relation: string; reason: string; } export function generateReport( kg: KnowledgeGraph, stats: GraphStats, root: string, fileCount: number, byExtension: Record, ): string { const lines: string[] = []; lines.push("# Mind Place Report"); lines.push(""); lines.push(`Generated from \`${root}\``); lines.push(""); // Corpus lines.push("## Corpus"); lines.push(""); lines.push(`- **Files scanned:** ${fileCount}`); if (Object.keys(byExtension).length > 0) { lines.push(`- **Languages:** ${Object.entries(byExtension).map(([ext, n]) => `${n} ${ext}`).join(", ")}`); } lines.push(""); // Graph stats lines.push("## Graph Statistics"); lines.push(""); lines.push(`| Metric | Value |`); lines.push(`|--------|-------|`); lines.push(`| Nodes | ${stats.nodeCount} |`); lines.push(`| Edges | ${stats.edgeCount} |`); lines.push(`| Communities | ${stats.communityCount} |`); lines.push(`| Avg. Degree | ${stats.nodeCount > 0 ? (stats.edgeCount * 2 / stats.nodeCount).toFixed(1) : "0"} |`); lines.push(""); // God nodes lines.push("## God Nodes"); lines.push(""); lines.push("The most-connected entities - these are the architectural pillars:"); lines.push(""); lines.push("| # | Node | Type | Connections | File |"); lines.push("|---|------|------|-------------|------|"); for (let i = 0; i < stats.godNodes.length; i++) { const god = stats.godNodes[i]; const node = kg.nodes.get(god.id); lines.push(`| ${i + 1} | **${god.label}** | ${node?.type ?? "?"} | ${god.degree} | \`${node?.sourceFile ?? "?"}\` |`); } lines.push(""); // Community overview if (stats.communityCount > 1) { lines.push("## Communities"); lines.push(""); lines.push("The graph was partitioned into these subsystems:"); // Gather community info with named labels const commMap = new Map(); for (const node of kg.nodes.values()) { if (node.community === undefined) continue; const c = commMap.get(node.community) ?? { size: 0, top: [], label: "" }; c.size++; if (c.top.length < 3) c.top.push(node.label); // Use the highest-centrality node as the community label if (!c.label || (node.centrality ?? 0) > (kg.nodes.get(c.label)?.centrality ?? 0)) { c.label = node.label; } commMap.set(node.community, c); } lines.push(""); lines.push("| Community | Size | Key Members |"); lines.push("|-----------|------|-------------|"); for (const [, info] of [...commMap.entries()].sort((a, b) => b[1].size - a[1].size)) { lines.push(`| **${info.label}** | ${info.size} | ${info.top.join(", ")} |`); } lines.push(""); } // Surprising connections const surprises = findSurprises(kg); if (surprises.length > 0) { lines.push("## Surprising Connections"); lines.push(""); for (const s of surprises.slice(0, 10)) { lines.push(`- **${s.source}** → \`${s.relation}\` → **${s.target}**: ${s.reason}`); } lines.push(""); } // Suggested questions const questions = suggestQuestions(kg, stats); if (questions.length > 0) { lines.push("## Suggested Questions"); lines.push(""); for (const q of questions.slice(0, 8)) { lines.push(`- ${q}`); } lines.push(""); } lines.push("---"); lines.push(`_Report generated by pi-mindplace · Use \`mindplace_query\` to explore the graph_`); lines.push(""); return lines.join("\n"); } function findSurprises(kg: KnowledgeGraph): Surprise[] { const surprises: Surprise[] = []; const communities = new Map(); for (const node of kg.nodes.values()) { if (node.community !== undefined) communities.set(node.id, node.community); } // Map community ID to its best label const commLabels = new Map(); for (const node of kg.nodes.values()) { if (node.community === undefined) continue; const best = commLabels.get(node.community); const bestNode = best ? kg.nodes.get(best) : null; if (!best || (node.centrality ?? 0) > (bestNode?.centrality ?? 0)) { commLabels.set(node.community, node.id); } } function commName(id: string): string { const c = communities.get(id); if (c === undefined) return "?"; const bestId = commLabels.get(c); return bestId ? (kg.nodes.get(bestId)?.label ?? `C${c}`) : `C${c}`; } for (const edge of kg.edges) { const sc = communities.get(edge.source); const tc = communities.get(edge.target); if (sc !== undefined && tc !== undefined && sc !== tc) { const srcLabel = kg.nodes.get(edge.source)?.label ?? edge.source; const tgtLabel = kg.nodes.get(edge.target)?.label ?? edge.target; if (edge.confidence !== "EXTRACTED") continue; surprises.push({ source: srcLabel, target: tgtLabel, relation: edge.relation, reason: `Cross-community bridge between "${commName(edge.source)}" and "${commName(edge.target)}"`, }); } } return surprises; } function suggestQuestions(kg: KnowledgeGraph, stats: GraphStats): string[] { const questions: string[] = []; // Questions about god nodes const top = stats.godNodes.slice(0, 3); if (top.length >= 2) { questions.push(`How does **${top[0].label}** connect to **${top[1].label}**?`); } if (top.length >= 1) { questions.push(`What calls **${top[0].label}** and what does it depend on?`); } // Cross-community bridges const communities = new Map(); for (const node of kg.nodes.values()) { if (node.community === undefined) continue; const c = communities.get(node.community) ?? []; c.push(node.label); communities.set(node.community, c); } const commEntries = [...communities.entries()].sort((a, b) => b[1].length - a[1].length); if (commEntries.length >= 2) { const examples = commEntries.slice(0, 2).map(c => c[1][0]); if (examples.length >= 2) { questions.push(`Trace the data flow between **${examples[0]}** and **${examples[1]}**`); } } // Type-based questions const importEdges = kg.edges.filter(e => e.relation === "imports").length; if (importEdges > 5) { questions.push(`Which modules have the most dependencies?`); } questions.push(`Show me the architecture of the \`${top[0]?.label ?? "main"}\` subsystem`); questions.push(`What is the most heavily connected module in the codebase?`); return questions; }