Files
boshu2__agentops/cli/internal/initapp/initapp_test.go
Bo 6bb54bb347 fix(cli): ao init creates the complete evidence layout (#938)
A fresh `ao init` was immediately flagged by the CLI's own diagnostics —
`ao doctor diff` reported `fm-knowledge-missing-substructure` (sessions,
index missing) and the `.agents/ao/intents/sha256` store that `ao
status` reads was never created. This was the last first-run wart from
the [3.3 release-readiness
audit](docs/audits/release-readiness-3.3-2026-07-20.md) (agents-runtime
minor 3).

**Fix:** `evidenceDirs` now derives the knowledge substructure from the
storage package's exported contract (`DefaultBaseDir` +
`SessionsDir`/`IndexDir`/`ProvenanceDir`) instead of a parallel
hand-list, and adds the intents store — so init, status, and doctor
agree on one layout by construction.

**Verified:** RED reproduced in a sandbox (P2 finding on fresh init),
GREEN after fix (finding gone, status reads both stores); new initapp
tests assert both contracts on the created tree and that dry-run touches
nothing; full suite 61/61 packages; `ao gate check --full` 67/67 over
this range.
2026-07-20 14:41:16 -04:00

64 lines
2.1 KiB
Go

package initapp
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"github.com/boshu2/agentops/cli/internal/storage"
)
// A fresh `ao init` must satisfy the CLI's own diagnostics: the knowledge-store
// substructure doctor enforces (storage sessions/index/provenance contract) and
// both loop-evidence stores status reads (intents, verdicts). Regression guard
// for the 3.3 audit finding where doctor flagged a just-initialized store.
func TestRun_CreatesLayoutSatisfyingDoctorAndStatusContracts(t *testing.T) {
t.Chdir(t.TempDir())
var out bytes.Buffer
if err := Run(RunOptions{Stdout: &out}); err != nil {
t.Fatalf("Run: %v", err)
}
mustBeDir := func(rel string) {
t.Helper()
info, err := os.Stat(rel)
if err != nil || !info.IsDir() {
t.Errorf("init did not create directory %s (err=%v)", rel, err)
}
}
// Doctor's knowledge-store contract: sessions/index/provenance under the
// storage base (fm-knowledge-missing-substructure fires on any missing one).
for _, sub := range []string{storage.SessionsDir, storage.IndexDir, storage.ProvenanceDir} {
mustBeDir(filepath.Join(storage.DefaultBaseDir, sub))
}
// Status's loop-evidence stores: intents and verdicts content stores.
mustBeDir(filepath.Join(storage.DefaultBaseDir, "intents", "sha256"))
mustBeDir(filepath.Join(storage.DefaultBaseDir, "verdicts", "sha256"))
// Session handoff evidence directory.
mustBeDir(filepath.Join(".agents", "handoff"))
if got := strings.Count(out.String(), "created "); got != len(evidenceDirs) {
t.Errorf("expected %d 'created' lines, got %d:\n%s", len(evidenceDirs), got, out.String())
}
}
func TestRun_DryRunCreatesNothing(t *testing.T) {
t.Chdir(t.TempDir())
var out bytes.Buffer
if err := Run(RunOptions{DryRun: true, Stdout: &out}); err != nil {
t.Fatalf("Run dry-run: %v", err)
}
if got := strings.Count(out.String(), "would create "); got != len(evidenceDirs) {
t.Errorf("expected %d 'would create' lines, got %d:\n%s", len(evidenceDirs), got, out.String())
}
if _, err := os.Stat(".agents"); !os.IsNotExist(err) {
t.Errorf("dry-run created .agents (stat err=%v); want nothing on disk", err)
}
}