Feature 09: AI harness and skills framework (#62)
CI / ci (pull_request) Successful in 1m34s
CI / ci (push) Successful in 1m36s

Co-authored-by: dev_agent <dev_agent@cubecraftlabs.com>
This commit was merged in pull request #62.
This commit is contained in:
2026-10-05 11:18:53 -04:00
committed by approver_agent
parent 8adbd2d7c2
commit 72fa311de9
36 changed files with 5368 additions and 11 deletions
+75 -4
View File
@@ -175,8 +175,8 @@ func TestMigrateEmbeddedMigrations(t *testing.T) {
if err := Migrate(context.Background(), s.Writer, migrations.FS); err != nil {
t.Fatal(err)
}
if got := versions(migrationRows(t, s)); got != "0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai" {
t.Errorf("versions = %q, want 0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai", got)
if got := versions(migrationRows(t, s)); got != "0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai,0006_ai_runs_status" {
t.Errorf("versions = %q, want 0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai,0006_ai_runs_status", got)
}
}
@@ -196,8 +196,8 @@ func TestMigrateBootstrapThenEmbeddedInitApplies(t *testing.T) {
if err := Migrate(ctx, s.Writer, migrations.FS); err != nil {
t.Fatal(err)
}
if got := versions(migrationRows(t, s)); got != "0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai" {
t.Errorf("versions = %q, want 0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai", got)
if got := versions(migrationRows(t, s)); got != "0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai,0006_ai_runs_status" {
t.Errorf("versions = %q, want 0000_bootstrap,0001_init,0002_household_settings_updated_by,0003_jobs_status,0004_ai_provider_presets,0005_ai_provider_xai,0006_ai_runs_status", got)
}
if !tableExists(t, s, "dinners") {
t.Error("table from 0001_init was not created")
@@ -486,3 +486,74 @@ func TestMigrateAIProviderXAIKeepsRowsAndReferences(t *testing.T) {
}
}
}
// TestMigrateAIRunsStatus upgrades a database at 0005 and checks 0006
// keeps an ok run and its references, accepts every harness outcome, and
// stops on a run with a pre-harness status rather than guess its outcome.
func TestMigrateAIRunsStatus(t *testing.T) {
ctx := context.Background()
before := fstest.MapFS{}
for _, name := range []string{"0000_bootstrap.sql", "0001_init.sql", "0002_household_settings_updated_by.sql", "0003_jobs_status.sql", "0004_ai_provider_presets.sql", "0005_ai_provider_xai.sql"} {
body, err := fs.ReadFile(migrations.FS, name)
if err != nil {
t.Fatal(err)
}
before[name] = &fstest.MapFile{Data: body}
}
seedRun := func(t *testing.T, s *Store, status string) {
t.Helper()
if err := Migrate(ctx, s.Writer, before); err != nil {
t.Fatal(err)
}
for _, stmt := range []string{
`INSERT INTO ai_runs (id, skill, skill_version, provider, model, temperature, status, latency_ms, tokens_in, tokens_out, error, request_redacted, response_redacted, created_at, updated_at)
VALUES ('run-1', 'suggest', '1', 'xai', 'grok', 0.5, '` + status + `', 10, 20, 30, 'e', 'req', 'resp', 'c', 'u')`,
`INSERT INTO suggestion_batches (id, trigger, status, ai_run_id, created_at, updated_at)
VALUES ('batch-1', 'manual', 'done', 'run-1', 'c', 'u')`,
} {
if _, err := s.Writer.Exec(stmt); err != nil {
t.Fatalf("seed: %v", err)
}
}
}
t.Run("ok row kept", func(t *testing.T) {
s := openTestStore(t)
seedRun(t, s, "ok")
if err := Migrate(ctx, s.Writer, migrations.FS); err != nil {
t.Fatal(err)
}
var status, request string
if err := s.Reader.QueryRow(`SELECT status, request_redacted FROM ai_runs WHERE id = 'run-1'`).Scan(&status, &request); err != nil {
t.Fatal(err)
}
if status != "ok" || request != "req" {
t.Errorf("ai_runs row = %s, %s; want ok, req", status, request)
}
if _, err := s.Writer.Exec(`DELETE FROM ai_runs WHERE id = 'run-1'`); err == nil || !strings.Contains(err.Error(), "FOREIGN KEY constraint failed") {
t.Errorf("deleting a referenced ai_run: error %v, want FOREIGN KEY constraint failure", err)
}
for _, status := range []string{"repaired", "bad_output", "provider_error", "ok"} {
if _, err := s.Writer.Exec(`UPDATE ai_runs SET status = ? WHERE id = 'run-1'`, status); err != nil {
t.Errorf("ai_runs.status %s rejected: %v", status, err)
}
}
if tableExists(t, s, "ai_runs_copy") {
t.Error("ai_runs_copy left behind")
}
})
for _, legacy := range []string{"running", "error"} {
t.Run(legacy+" row stops the migration", func(t *testing.T) {
s := openTestStore(t)
seedRun(t, s, legacy)
if err := Migrate(ctx, s.Writer, migrations.FS); err == nil || !strings.Contains(err.Error(), "CHECK constraint failed") {
t.Fatalf("Migrate error = %v, want a CHECK constraint failure", err)
}
var status string
if err := s.Reader.QueryRow(`SELECT status FROM ai_runs WHERE id = 'run-1'`).Scan(&status); err != nil || status != legacy {
t.Errorf("after the failed migration status = %q, %v; want %q kept", status, err, legacy)
}
})
}
}