Files
Bo 3d24ee0e9d fix(cli): residue wave — doctor dev-version coherence, diff --only, config-models removal, dual-root stragglers (#944)
Wave 4 (residue) of the new-user happy-path arc. Three scoped
implementer lanes + fresh adversarial verifier (4 RESOLVED; 1 INCOMPLETE
= stale generated projections, closed in integration).

**Doctor**: the dev-version detector now reuses the Binary Freshness
resolution — a from-source build matching its checkout is healthy (a
novice building from source can finally see `ao doctor` exit 0);
findings fire only on genuine drift, shadowed duplicate `ao` binaries,
or an informational from-source note outside any checkout. `ao doctor
diff` gains `--only` so the fix-plan preview can be scoped the way
remediation text implies.

**Config**: the dead `ao config models` surface is removed end-to-end
(lane re-verified zero consumers before deleting; `--show` proven
byte-identical before/after; removed-child hint + MIGRATION row;
existing `models:` config sections still parse and are ignored).

**Dual-root stragglers**: learning-coherence gate globs,
`quality.CountConstraints`, and the eval sandbox corpus deny-list now
cover canonical `.agents/ao/<section>` alongside legacy roots.

**Doc-link hygiene**: the strict docs-link backstop's allowlist was 100%
stale (53/53 entries referenced Cathedral-Cut-deleted docs) — refreshed
to 10 verified accepted-class entries; ROADMAP dead links fixed;
documentation-index generator emits GitHub URLs for repo-root targets;
doc-skill references instruct only shipped scripts; codex twins +
CLI-surface projections + surface-count fixture regenerated.

**Deferred by design**: the `3.3.0-rc` fallback version bump belongs
inside the v3.3.0 tag-cut commit.

**Verified**: full suite 61/61 pkgs (2825 tests); golangci-lint clean;
`ao gate check --full` 67/67 over this range; Test-Removal-Reason
trailer covers the 6 deliberately deleted models tests.
2026-07-20 19:05:57 -04:00

81 lines
2.6 KiB
Go

package config
import (
"context"
"os"
"path/filepath"
"testing"
)
type fakeCommandGateway struct{}
func (gateway *fakeCommandGateway) Resolve(string, bool) *ResolvedConfig { return &ResolvedConfig{} }
func (gateway *fakeCommandGateway) Files() (ConfigFiles, error) { return ConfigFiles{}, nil }
func (gateway *fakeCommandGateway) Environment([]string) map[string]string {
return map[string]string{}
}
// TestCommandServiceShowReportsLegacyReadPaths pins the files-panel half of
// novice edge 8: when the deprecated home fallback is active, ShowResult must
// carry the path actually read so the renderer can label it instead of
// reporting the canonical path as missing.
func TestCommandServiceShowReportsLegacyReadPaths(t *testing.T) {
clearConfigEnv(t)
isolateLegacyWarnings(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Chdir(t.TempDir())
legacy := filepath.Join(home, ".agentops", "config.yaml")
if err := os.MkdirAll(filepath.Dir(legacy), 0o755); err != nil {
t.Fatalf("mkdir legacy dir: %v", err)
}
if err := os.WriteFile(legacy, []byte("output: json\n"), 0o644); err != nil {
t.Fatalf("write legacy config: %v", err)
}
result, err := NewCommandService(&fakeCommandGateway{}).Show(context.Background(), "", false)
if err != nil {
t.Fatal(err)
}
files := result.ConfigFiles
if !files.HomeLegacy {
t.Fatal("HomeLegacy = false, want true when only the legacy home config exists")
}
if files.HomeReadPath != legacy {
t.Errorf("HomeReadPath = %q, want %q", files.HomeReadPath, legacy)
}
if files.ProjectLegacy {
t.Error("ProjectLegacy = true, want false with no project config at all")
}
}
// TestCommandServiceShowCanonicalReadPath: with the canonical home config in
// place the read path equals it and no legacy label is requested.
func TestCommandServiceShowCanonicalReadPath(t *testing.T) {
clearConfigEnv(t)
isolateLegacyWarnings(t)
home := t.TempDir()
t.Setenv("HOME", home)
t.Chdir(t.TempDir())
canonical := filepath.Join(home, ".agents", "ao", "config.yaml")
if err := os.MkdirAll(filepath.Dir(canonical), 0o755); err != nil {
t.Fatalf("mkdir config dir: %v", err)
}
if err := os.WriteFile(canonical, []byte("output: json\n"), 0o644); err != nil {
t.Fatalf("write config: %v", err)
}
result, err := NewCommandService(&fakeCommandGateway{}).Show(context.Background(), "", false)
if err != nil {
t.Fatal(err)
}
if result.ConfigFiles.HomeLegacy {
t.Fatal("HomeLegacy = true, want false when the canonical home config exists")
}
if result.ConfigFiles.HomeReadPath != canonical {
t.Errorf("HomeReadPath = %q, want %q", result.ConfigFiles.HomeReadPath, canonical)
}
}