Files
zzet--gortex/internal/mcp/tools_analyze_temporal.go
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

66 lines
2.4 KiB
Go

package mcp
import (
"context"
"github.com/mark3labs/mcp-go/mcp"
"github.com/zzet/gortex/internal/resolver"
)
// handleAnalyzeTemporalOrphans is the queryable face of the Temporal
// call-graph integrity check: broken dispatches (a workflow calls an
// activity/child-workflow that resolves to nothing), signals/queries with
// no handler, and registered activities/workflows nobody dispatches or
// starts. Exposed as `analyze kind=temporal_orphans`.
func (s *Server) handleAnalyzeTemporalOrphans(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
rep := resolver.DetectTemporalOrphans(s.graph)
if s.scopeFiltersActive(ctx) {
// Narrow each integrity-gap list to entries whose subject node is
// visible to the request (workspace ceiling + optional repo
// allow-set); the inline response below then recomputes totals
// from the filtered lengths. TemporalOrphan.From and the
// OrphanActivity / OrphanWorkflow strings are the node IDs; Name
// is a Temporal contract name (not a node), so it never leaks.
// Filtered at the MCP layer only — the resolver stays
// scope-agnostic. Unbound requests skip this branch — a no-op.
keepOrphans := func(in []resolver.TemporalOrphan) []resolver.TemporalOrphan {
out := make([]resolver.TemporalOrphan, 0, len(in))
for _, o := range in {
if s.analyzeNodeVisible(ctx, s.graph.GetNode(o.From)) {
out = append(out, o)
}
}
return out
}
keepIDs := func(in []string) []string {
out := make([]string, 0, len(in))
for _, id := range in {
if s.analyzeNodeVisible(ctx, s.graph.GetNode(id)) {
out = append(out, id)
}
}
return out
}
rep.BrokenDispatch = keepOrphans(rep.BrokenDispatch)
rep.SignalNoHandler = keepOrphans(rep.SignalNoHandler)
rep.QueryNoHandler = keepOrphans(rep.QueryNoHandler)
rep.OrphanActivity = keepIDs(rep.OrphanActivity)
rep.OrphanWorkflow = keepIDs(rep.OrphanWorkflow)
}
return s.respondJSONOrTOON(ctx, req, map[string]any{
"broken_dispatch": rep.BrokenDispatch,
"signal_no_handler": rep.SignalNoHandler,
"query_no_handler": rep.QueryNoHandler,
"orphan_activity": rep.OrphanActivity,
"orphan_workflow": rep.OrphanWorkflow,
"totals": map[string]int{
"broken_dispatch": len(rep.BrokenDispatch),
"signal_no_handler": len(rep.SignalNoHandler),
"query_no_handler": len(rep.QueryNoHandler),
"orphan_activity": len(rep.OrphanActivity),
"orphan_workflow": len(rep.OrphanWorkflow),
},
})
}