Remove AI config approval flow

This commit is contained in:
npc0-hue
2026-09-22 15:33:32 +08:00
parent 20008b4043
commit a8b5d483a3
54 changed files with 364 additions and 875 deletions
+11 -35
View File
@@ -72,7 +72,7 @@ func TestPluginLifecycleBridgeDispatchesBoundedJob(t *testing.T) {
}
}
func TestAIConfigRecommendationRequiresApprovalAndRejectsStaleRevision(t *testing.T) {
func TestAIConfigRecommendationDispatchesConfigWriteImmediately(t *testing.T) {
svc, session, instance := newPluginOperationsFixture(t)
provider, err := svc.CreateAIProvider(domain.AIProvider{ID: "ai-local", Name: "Local AI", Kind: domain.AIProviderKindOllama, BaseURL: "http://127.0.0.1:11434/v1", Models: []string{"test-model"}, DefaultModel: "test-model", RelayMode: domain.AIRelayModeLocal, TimeoutMS: 1000, Status: domain.AIProviderStatusActive, RedactionPolicy: "strict"})
if err != nil {
@@ -82,43 +82,19 @@ func TestAIConfigRecommendationRequiresApprovalAndRejectsStaleRevision(t *testin
if err != nil {
t.Fatalf("invoke AI: %v", err)
}
if response.ConfigRecommendation == nil || response.ConfigRecommendation.DiffID == "" {
t.Fatalf("expected persisted config recommendation, got %+v", response)
if response.ConfigRecommendation == nil || response.ConfigExecution == nil || response.ConfigExecution.Job.ID == "" {
t.Fatalf("expected direct config write dispatch, got %+v", response)
}
if response.ConfigExecution.Job.Capability != domain.JobCapabilityConfigWrite || response.ConfigExecution.Status != "queued" {
t.Fatalf("unexpected AI config execution: %+v", response.ConfigExecution)
}
jobs, _ := svc.store.Jobs().List(domain.JobFilter{ServerInstanceID: instance.ID})
if len(jobs) != 0 {
t.Fatalf("AI recommendation must not dispatch before approval: %+v", jobs)
if len(jobs) != 1 || jobs[0].ID != response.ConfigExecution.Job.ID {
t.Fatalf("AI recommendation must dispatch exactly one config write job: %+v", jobs)
}
approved, err := svc.ApproveAIConfigDiffForSession(session, domain.AIConfigDiffApprovalRequest{DiffID: response.ConfigRecommendation.DiffID, IdempotencyKey: "approve-ai-config-1"})
if err != nil {
t.Fatalf("approve AI diff: %v", err)
}
if approved.Preview.State != domain.AIConfigDiffStateApproved || approved.Dispatch.Job.ID == "" {
t.Fatalf("expected approved diff and queued job, got %+v", approved)
}
repeated, err := svc.ApproveAIConfigDiffForSession(session, domain.AIConfigDiffApprovalRequest{DiffID: response.ConfigRecommendation.DiffID, IdempotencyKey: "approve-ai-config-1"})
if err != nil || repeated.Dispatch.Job.ID != approved.Dispatch.Job.ID {
t.Fatalf("repeat approval must return original job: %+v err=%v", repeated, err)
}
jobs, _ = svc.store.Jobs().List(domain.JobFilter{ServerInstanceID: instance.ID})
if len(jobs) != 1 {
t.Fatalf("approval must dispatch exactly one job, got %+v", jobs)
}
staleResponse, err := svc.InvokeAIForSession(session, domain.AIInvocationRequest{RequestID: "ai-config-stale", ServerInstanceID: instance.ID, ProviderID: provider.ID, Purpose: "config.suggest", Prompt: "disable pvp"})
if err != nil {
t.Fatalf("invoke stale AI candidate: %v", err)
}
stored, err := svc.store.ServerInstances().Get(instance.ID)
if err != nil {
t.Fatalf("get server: %v", err)
}
stored.ConfigVersion++
if err := svc.store.ServerInstances().Update(stored); err != nil {
t.Fatalf("advance config revision: %v", err)
}
if _, err := svc.ApproveAIConfigDiffForSession(session, domain.AIConfigDiffApprovalRequest{DiffID: staleResponse.ConfigRecommendation.DiffID, IdempotencyKey: "approve-stale"}); err == nil || !strings.Contains(err.Error(), "expectedConfigVersion") {
t.Fatalf("expected stale revision rejection, got %v", err)
repeated, err := svc.InvokeAIForSession(session, domain.AIInvocationRequest{RequestID: "ai-config-1", ServerInstanceID: instance.ID, ProviderID: provider.ID, Purpose: "config.suggest", Prompt: "disable pvp"})
if err != nil || repeated.ConfigExecution == nil || repeated.ConfigExecution.Job.ID != response.ConfigExecution.Job.ID {
t.Fatalf("repeat AI request must reuse the idempotent job: %+v err=%v", repeated, err)
}
}