Skip to content

Insights v2: add single-binary offline analysis - #15

Merged
zroubalik merged 10 commits into
kedify:mainfrom
zroubalik:insights-v2-offline-analysis
Sep 8, 2026
Merged

zroubalik merged 10 commits into
kedify:mainfrom
zroubalik:insights-v2-offline-analysis

Conversation

@zroubalik

@zroubalik zroubalik commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Why

Users should run offline recommendation analysis with only the public Kedify CLI. The CLI and Dashboard API must use the same calculation implementation.

What

  • Add kedify analyze recommendations for a normalized snapshot file or stdin.
  • Import the public github.com/kedify/recommender/analysis package and call it in-process.
  • Return the engine output directly, including schema, detector, policy, evidence, data quality, and recommendations.
  • Reject malformed, unsupported, and oversized snapshot input.
  • Document a useful request with targets, CPU millicores, memory bytes, and missing-signal semantics.
  • Keep execution independent of Kedify credentials and network access.
  • Update Staticcheck to a version compatible with the repository Go version.

There is no analyzer subprocess, executable discovery, runtime download, or private Go dependency. Prometheus and Kubernetes source adapters remain tracked by kedify/agent#618 and #14.

Verification

  • go test -count=1 -race ./...
  • go vet ./...
  • clean build through proxy.golang.org with private-module settings disabled
  • built CLI analyzed a non-empty normalized snapshot successfully

Dependency

The licensed public module is released as v0.1.0 and pinned here. Dashboard API #524 pins the same version.

Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
@zroubalik
zroubalik requested a review from a team as a code owner September 7, 2026 17:47
Copilot AI lite review requested due to automatic review settings September 7, 2026 17:47
Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The implementation matches the stated offline invocation requirements and is covered by targeted tests, with only minor follow-up suggestions noted in review comments.

Pull request overview

Adds an offline “Insights v2” entry point to the public CLI by invoking a separately installed local analyzer binary and validating the request/response protocol so the CLI can produce machine-readable recommendations without importing private engine code or contacting Kedify SaaS.

Changes:

  • Introduces kedify analyze recommendations <snapshot-request> and wires it into the root CLI command tree.
  • Implements local analyzer discovery (explicit path → sibling binary → PATH), bounded I/O, exit-code propagation, and protocol/schema/version validation.
  • Documents the offline request envelope and usage in the README, and adds focused unit tests for discovery/validation/I-O/limits.
File summaries
File Description
README.md Documents offline analyzer invocation, discovery order, protocol/schema requirements, and size limits.
internal/cli/run.go Registers the new analyze command group and the analyze recommendations subcommand.
internal/cli/analyze/recommendations.go Implements snapshot ingestion, analyzer discovery/execution, response validation, and stdout/stderr behavior.
internal/cli/analyze/recommendations_test.go Adds tests covering stdin/file input, discovery order, protocol validation, size limits, and exit-code propagation.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/cli/analyze/recommendations.go Outdated
Comment thread internal/cli/analyze/recommendations.go Outdated
Copilot AI review requested due to automatic review settings September 7, 2026 17:51
@zroubalik
zroubalik requested a lite review from Copilot and removed request for Copilot September 7, 2026 17:53
@zroubalik
zroubalik requested a balanced review from Copilot September 7, 2026 17:54
Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Handle analyzer exits where ExitCode() == -1 before approval.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

internal/cli/analyze/recommendations.go:78

  • Handle the ExitCode() == -1 case before wrapping this error. Go returns -1 when the analyzer was terminated by a signal or otherwise has no exit code; passing that through CommandResultError makes the top-level CLI return an invalid, non-portable status and suppresses the useful termination error. Map only nonnegative child codes and return a wrapped error otherwise.
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 7, 2026 17:57
Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Analyzer signal termination and oversized-error handling do not correctly preserve exit behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread internal/cli/analyze/recommendations.go Outdated
Comment thread internal/cli/analyze/recommendations.go Outdated
Copilot AI review requested due to automatic review settings September 7, 2026 18:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Oversized analyzer output can hang execution and incorrectly override nonzero analyzer exit codes.

Review details

Suppressed comments (2)

internal/cli/analyze/recommendations.go:75

  • The response cap only limits retained memory: once the buffer is full, Write still reports every byte as successfully consumed, so command.Run() keeps draining stdout and waits for the analyzer to exit. An analyzer that continuously emits output can therefore hang the CLI indefinitely despite the documented 64 MiB limit. Abort/kill and reap the subprocess as soon as the first byte beyond the limit is observed.
	response := cappedBuffer{limit: maxAnalyzerResponseBytes}
	command.Stdout = &response
	runErr := command.Run()
	if response.exceeded {

internal/cli/analyze/recommendations.go:76

  • Handle a nonzero analyzer exit before checking response.exceeded. As written, an analyzer that writes more than 64 MiB and exits with (for example) code 2 is converted into a generic CLI error/exit 1, contradicting the promised exit-code preservation. The oversized-output check should apply after successful execution; a combined oversized-output/nonzero-exit regression test would cover this case.
	if response.exceeded {
		return fmt.Errorf("analyzer response exceeds %d-byte limit", maxAnalyzerResponseBytes)
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
Copilot AI review requested due to automatic review settings September 7, 2026 18:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The reviewed changes have no unresolved approval-blocking issues.

Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
Copilot AI review requested due to automatic review settings September 8, 2026 10:33
@zroubalik zroubalik changed the title Insights v2: invoke the local analyzer Insights v2: add single-binary offline analysis Sep 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The reviewed changes have no unresolved approval-blocking issues.

Review details
  • Files reviewed: 6/7 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The recommender must be updated to clamp confidence to 95 for intervals above 168 hours.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

go.mod:13

  • The pinned engine does not cap confidence at its maximumConfidence value: recommendationConfidence computes max(20, hours*95/168), so a valid snapshot with observedIntervalHours: 336 returns confidence 190. Since this command accepts any positive interval and exposes the result directly, pin an engine revision that clamps confidence to 95 (and covers intervals above 168 hours) before release.
  • Files reviewed: 6/7 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
Copilot AI review requested due to automatic review settings September 8, 2026 11:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

JSON output can silently succeed when only partially written; the success-path test also needs meaningful analysis data.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

internal/cli/analyze/recommendations.go:45

  • Structured command results elsewhere use ctx.WriteOutput, whose implementation detects n < len(data) (internal/output/output.go:43-49). json.Encoder.Encode does not detect a writer that short-writes without returning an error, so this command can exit successfully after emitting truncated JSON. Route this result through ctx.WriteOutput(..., "json") and initialize that dependency in these command tests.

internal/cli/analyze/recommendations_test.go:44

  • The only successful analysis fixture has no containers and this assertion requires an empty result, so the test never exercises the command's core promise of passing observations through to evidence, data-quality, and recommendation output. Use a non-empty normalized snapshot and assert at least one calculated result and its key fields; keep a separate empty-input case if that behavior also matters.
	if result.Results == nil || len(result.Results) != 0 {
		t.Fatalf("results = %#v, want an empty array", result.Results)
  • Files reviewed: 6/7 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@zroubalik
zroubalik merged commit 4e4bb92 into kedify:main Sep 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants