Files
zero/internal/cli/exec_self_correct_test.go
KRATOS 47c3cc8937 wedge stage 13: launch readiness (first-run + benchmark) (#186)
* stage 13: launch readiness (first-run + benchmark)

First-run, model-agnostic-first:
- provideronboarding: detect local OpenAI-compatible runtimes (Ollama/LM Studio)
  on their default ports and offer them with no API key required
- provideronboarding: ClassifySetupProbe maps a live connectivity probe to a
  specific, fixable error class (bad key, wrong base URL, model not found,
  rate limit, config) instead of a stack trace; never panics
- zero setup --verify: probe the provider after saving and report the fixable
  error on failure; print a concrete 'try this' headless example on success

zero doctor hardening:
- new sandbox.backend check (bubblewrap/sandbox-exec) with a platform-specific
  install remedy; warn (not fail) on policy-only fallback
- new lsp.servers check listing missing language servers with per-binary install
  remedies; injectable GOOS/LookupExecutable for deterministic tests

Self-correct surface + benchmark:
- zero exec --self-correct wires the post-edit verify-and-correct loop via the
  project verifier; nil corrector when off keeps the agent loop byte-identical
- perfbench task harness: reproducible Terminal-Bench-style runner over headless
  zero exec + stream-json; records model + commit + self-correct flag + date
- zero-perf-bench tasks subcommand (with --dry-run) and a sample task set
- docs/BENCHMARK.md: the number, the exact command, the model, and the
  with/without-self-correct methodology

* stage 13: address review (verify-state, fixture paths, run_end exit, 404 classification)

* stage 13: verifier inherits process environment (PATH/HOME/toolchain)
2026-06-13 11:10:37 +05:30

69 lines
2.1 KiB
Go

package cli
import (
"bytes"
"strings"
"testing"
)
func TestParseExecSelfCorrectFlag(t *testing.T) {
t.Run("absent defaults to false", func(t *testing.T) {
options, help, err := parseExecArgs([]string{"hello"})
if err != nil {
t.Fatalf("parseExecArgs returned error: %v", err)
}
if help {
t.Fatal("help = true, want false")
}
if options.selfCorrect {
t.Fatal("selfCorrect = true, want false by default")
}
})
t.Run("flag sets true", func(t *testing.T) {
options, _, err := parseExecArgs([]string{"--self-correct", "hello"})
if err != nil {
t.Fatalf("parseExecArgs returned error: %v", err)
}
if !options.selfCorrect {
t.Fatal("selfCorrect = false, want true")
}
if strings.Join(options.promptParts, " ") != "hello" {
t.Fatalf("promptParts = %#v, want [hello]", options.promptParts)
}
})
t.Run("flag rejects an inline value", func(t *testing.T) {
_, _, err := parseExecArgs([]string{"--self-correct=yes", "hello"})
if err == nil {
t.Fatal("expected an error for --self-correct=yes, got nil")
}
})
t.Run("rejects combination with --use-spec", func(t *testing.T) {
// --use-spec routes through the spec-draft (planning) path, which never wires
// the post-edit self-correct loop. Accepting --self-correct there would
// silently ignore it, so the combination is rejected at parse time.
_, _, err := parseExecArgs([]string{"--use-spec", "--self-correct", "hello"})
if err == nil {
t.Fatal("expected an error for --use-spec with --self-correct, got nil")
}
if !strings.Contains(err.Error(), "--self-correct") || !strings.Contains(err.Error(), "--use-spec") {
t.Fatalf("error should name both flags, got %q", err.Error())
}
})
}
func TestRunExecHelpDocumentsSelfCorrect(t *testing.T) {
var stdout bytes.Buffer
var stderr bytes.Buffer
exitCode := Run([]string{"exec", "--help"}, &stdout, &stderr)
if exitCode != 0 {
t.Fatalf("expected exit code 0, got %d", exitCode)
}
if !strings.Contains(stdout.String(), "--self-correct") {
t.Fatalf("expected exec help to document --self-correct, got %q", stdout.String())
}
}