[Repo Assist] feat(diagnose): add --format json flag with structured DiagnoseReport output#4571
Conversation
… output Add DiagnoseReport struct with HealthScore (0-100) and Findings slice to pkg/k8s/diagnostics.go. Introduce DiagnoseClusterReport() alongside the existing DiagnoseCluster() so callers can request structured output without breaking the default text path. Wire --format flag (text|json) into ksail cluster diagnose. When --format json is passed, the command marshals a DiagnoseReport to stdout, making the cluster_read MCP tool useful for AI assistants that need numeric health signals and structured finding data rather than free-form text. Each critical finding (not-ready node, failing pod) deducts 25 points from the 100-point HealthScore; warnings deduct 10 points; score floors at 0. Closes #4422 (partial — structured scoring + JSON output path) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅MegaLinter analysis: Success✅ Linters with no issuesactionlint, git_diff, hadolint, jscpd, jsonlint, lychee, markdown-table-formatter, markdownlint, prettier, prettier, stylelint, syft, trivy-sbom, trufflehog, v8r, v8r, yamllint See detailed reports in MegaLinter artifacts
|
There was a problem hiding this comment.
Pull request overview
This PR adds machine-readable JSON output to ksail cluster diagnose so diagnosis data can be consumed by MCP/chat tooling without parsing free-form text. It extends the existing Kubernetes diagnostics flow with a structured report type and exposes it through a new CLI flag on the cluster command.
Changes:
- Added structured diagnosis types and
DiagnoseClusterReport()inpkg/k8swith severity-tagged findings and a computed health score. - Added
--formattoksail cluster diagnoseand wired--format jsonto emit indented JSON instead of the existing text output. - Added unit coverage for the new report builder and a command-construction test for the new flag.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
pkg/k8s/diagnostics.go |
Introduces structured diagnosis models and JSON-oriented report generation. |
pkg/k8s/diagnostics_test.go |
Adds report-focused tests for scoring and error propagation. |
pkg/cli/cmd/cluster/cluster.go |
Adds the new --format flag and JSON output branch for cluster diagnose. |
pkg/cli/cmd/cluster/cluster_test.go |
Verifies the new diagnose flag is registered with the expected default. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.
| Benchmark suite | Current: 2fbcc29 | Previous: f3bb082 | Ratio |
|---|---|---|---|
BenchmarkCluster_MarshalJSON/FullProductionCluster (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) |
179127 ns/op 20591 B/op 463 allocs/op |
66775 ns/op 20581 B/op 463 allocs/op |
2.68 |
BenchmarkCluster_MarshalJSON/FullProductionCluster (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) - ns/op |
179127 ns/op |
66775 ns/op |
2.68 |
BenchmarkYAMLEncode/Minimal (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) |
162826 ns/op 21240 B/op 386 allocs/op |
61046 ns/op 21240 B/op 386 allocs/op |
2.67 |
BenchmarkYAMLEncode/Minimal (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) - ns/op |
162826 ns/op |
61046 ns/op |
2.67 |
BenchmarkYAMLEncode/FullProductionCluster (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) |
212015 ns/op 32368 B/op 431 allocs/op |
70106 ns/op 32368 B/op 431 allocs/op |
3.02 |
BenchmarkYAMLEncode/FullProductionCluster (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) - ns/op |
212015 ns/op |
70106 ns/op |
3.02 |
BenchmarkJSONEncode (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) |
153337 ns/op 15754 B/op 382 allocs/op |
58769 ns/op 15751 B/op 382 allocs/op |
2.61 |
BenchmarkJSONEncode (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) - ns/op |
153337 ns/op |
58769 ns/op |
2.61 |
BenchmarkPruneClusterDefaults/MostlyDefaults (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) |
52036 ns/op 7856 B/op 225 allocs/op |
27682 ns/op 7856 B/op 225 allocs/op |
1.88 |
BenchmarkPruneClusterDefaults/MostlyDefaults (github.com/devantler-tech/ksail/v7/pkg/apis/cluster/v1alpha1) - ns/op |
52036 ns/op |
27682 ns/op |
1.88 |
This comment was automatically generated by workflow using github-action-benchmark.
Add early validation for the --format flag in runDiagnoseCmd that normalises the value to lower-case and returns ErrUnsupportedOutputFormat for any value other than "text" or "json". This prevents typos like --format jsn from silently falling back to the text path, which would cause MCP/automation callers to receive prose when they expected JSON. Reuses the existing ErrUnsupportedOutputFormat sentinel and outputFormatText/outputFormatJSON constants for consistency with the --output flag validation pattern already in this package. Also add: - TestDiagnoseCmd_InvalidFormatRejectsEarly to cover the new guard - TestDiagnoseClusterReport_PodListErrorCreatesWarningFinding to cover the DiagnoseSeverityWarning path in DiagnoseClusterReport Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Extract score calculation into diagnoseComputeScore to reduce cyclomatic complexity of DiagnoseClusterReport from 13 to below the max of 10 - Extract pod-listing loop into appendNamespacePodFindings for the same reason - Replace magic numbers 100/25/10 with named constants (diagnoseMaxHealthScore, diagnoseCriticalPenalty, diagnoseWarningPenalty) - Wrap json.Encoder.Encode error to satisfy wrapcheck linter Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Split long function signatures (>120 chars) for DiagnoseClusterReport and appendNamespacePodFindings across multiple lines (lll) - Extract runDiagnoseJSONReport helper to keep runDiagnoseCmd within the 60-line limit (funlen) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
golangci-lint auto-formats imports on each run; pre-applying this avoids the git-auto-commit-action conflicting during CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…v5, gofmt) Fix import ordering in cluster.go to match gci's expected section order (standard → devantler-tech prefix → external), split enc.Encode assignment per wsl_v5 requirement, and fix indentation in diagnostics_test.go. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

🤖 This is an automated PR from Repo Assist.
Summary
Adds structured JSON output support to
ksail cluster diagnose, directly advancing the roadmap "Next" item: "enriched MCP tool output (cluster_readtool surfaces diagnosis data for AI assistants)".What changed
pkg/k8s/diagnostics.go— new types and function:DiagnoseSeverity(critical/warning)DiagnoseFinding— resource, reason, severity per unhealthy itemDiagnoseReport— cluster name,healthScore(0–100), andfindingssliceDiagnoseClusterReport()— structured equivalent of the existingDiagnoseCluster(); existing text path is unchangedpkg/cli/cmd/cluster/cluster.go— new--formatflag:text— existing behaviour preserved exactly--format json— marshals aDiagnoseReportas indented JSON to stdoutHealth scoring: starts at 100, deducts 25 per critical finding (not-ready node, failing pod), deducts 10 per warning, floors at 0.
Example JSON output
{ "clusterName": "my-cluster", "healthScore": 75, "findings": [ { "severity": "critical", "resource": "pod/crash-demo (default)", "reason": "crash-demo: CrashLoopBackOff for myimage:latest (3 restarts)" } ] }Why this matters
The
cluster_readMCP tool is auto-generated fromksail cluster diagnose. AI assistants (Claude, Copilot) that callcluster_readcurrently receive free-form text. With--format jsonthe MCP server can pass a structured report — numeric health score + typed findings — that AI models can reason over without parsing prose.Type of change
Test Status
go build ./...— ✅ passesgo test ./pkg/k8s/... ./pkg/cli/cmd/cluster/...— ✅ passesgo vet ./pkg/k8s/... ./pkg/cli/cmd/cluster/...— ✅ passesDiagnoseClusterReportcovering: healthy cluster (score=100), failing pod (score=75), not-ready node (score=75), score floor at zero, node list error surfacedPartial fix for #4422.