a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
77 lines
2.7 KiB
Go
77 lines
2.7 KiB
Go
// connectivity_health — a graph-EXTRACTION quality diagnostic.
|
|
//
|
|
// This analyzer reports the connectivity health of the knowledge graph
|
|
// itself: how many nodes are isolated (zero edges of any kind), how
|
|
// many are leaves / source-only / sink-only, the effective-vs-nominal
|
|
// graph size, and which source files contribute the most isolated /
|
|
// leaf nodes.
|
|
//
|
|
// It is deliberately DISTINCT from kind=dead_code. dead_code reports
|
|
// symbols with zero *incoming usage* edges — genuinely unreachable
|
|
// code, a real finding to act on (delete it). This analyzer reports
|
|
// isolated nodes — zero edges of *any* kind, structural edges
|
|
// included — which a normally extracted symbol never has. An isolated
|
|
// node signals the indexer mis-extracted the symbol or its file, not
|
|
// that the code is unused; the response carries a `note` spelling out
|
|
// the distinction so a reader does not delete live code.
|
|
|
|
package mcp
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
|
|
"github.com/zzet/gortex/internal/analysis"
|
|
)
|
|
|
|
// handleAnalyzeConnectivityHealth answers analyze kind=connectivity_health.
|
|
//
|
|
// It walks the session-scoped node set once, classifying each node via
|
|
// the shared graph.ClassifyZeroEdge (isolated == zero edges of any
|
|
// kind) and by in/out degree (leaf / source-only / sink-only), then
|
|
// rolls the isolated + leaf counts up per node kind and per source
|
|
// file.
|
|
//
|
|
// Args:
|
|
//
|
|
// - `limit`: cap the dead_weight_by_file ranking (default 50).
|
|
func (s *Server) handleAnalyzeConnectivityHealth(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
args := req.GetArguments()
|
|
fileLimit := 50
|
|
if v, ok := args["limit"].(float64); ok && v > 0 {
|
|
fileLimit = int(v)
|
|
}
|
|
|
|
report := analysis.GraphConnectivity(s.graph, s.scopedNodes(ctx), fileLimit)
|
|
|
|
if s.isGCX(ctx, req) {
|
|
return s.gcxResponseWithBudget(req)(encodeAnalyze("connectivity_health", report))
|
|
}
|
|
|
|
if isCompact(req) {
|
|
var b strings.Builder
|
|
fmt.Fprintf(&b, "effective %d / nominal %d (ratio %.3f)\n",
|
|
report.EffectiveNodes, report.NominalNodes, report.EffectiveRatio)
|
|
fmt.Fprintf(&b, "isolated %d leaf %d source_only %d sink_only %d\n",
|
|
report.Isolated, report.Leaf, report.SourceOnly, report.SinkOnly)
|
|
for _, k := range report.ByKind {
|
|
if k.Isolated == 0 && k.Leaf == 0 {
|
|
continue
|
|
}
|
|
fmt.Fprintf(&b, " %-12s total %-5d isolated %-4d leaf %d\n",
|
|
k.Kind, k.Total, k.Isolated, k.Leaf)
|
|
}
|
|
for _, f := range report.DeadWeightByFile {
|
|
fmt.Fprintf(&b, " %3d dead-weight %s (isolated %d, leaf %d)\n",
|
|
f.DeadWeight, f.FilePath, f.Isolated, f.Leaf)
|
|
}
|
|
b.WriteString("\nnote: " + report.Note + "\n")
|
|
return mcp.NewToolResultText(b.String()), nil
|
|
}
|
|
|
|
return s.respondJSONOrTOON(ctx, req, report)
|
|
}
|