Add golden-v1 hard-negative suite, shadow observability fields, query/command negation gates for high-risk writes, AllowAffirmative enforcement, candidate conflict clarification, and coordinator clarify-before-ambiguous ordering. Co-authored-by: Cursor <cursoragent@cursor.com>
94 lines
3.1 KiB
Go
94 lines
3.1 KiB
Go
package coordinator_test
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"chat-agent-system/internal/bizdev"
|
|
"chat-agent-system/internal/coordinator"
|
|
"chat-agent-system/internal/intent"
|
|
)
|
|
|
|
// TestEngine_ClarificationBeforeAmbiguousConsult 缺驳回理由必须返回定向澄清,不得进入参谋模糊咨询
|
|
func TestEngine_ClarificationBeforeAmbiguousConsult(t *testing.T) {
|
|
rec := intent.NewRecognizer()
|
|
engine := coordinator.NewCoordinatorEngine(nil)
|
|
|
|
ctx := &intent.ContextSnapshot{
|
|
SnapshotID: "ctx_engine_clarify",
|
|
CurrentStage: string(bizdev.StageV05_Feasibility),
|
|
ActiveDocID: "doc-002",
|
|
DocLifecycleState: "reviewing",
|
|
UserDocRole: "reviewer",
|
|
}
|
|
|
|
recRes, err := rec.Recognize(context.Background(), "把调研报告审核驳回", ctx)
|
|
if err != nil {
|
|
t.Fatalf("recognize failed: %v", err)
|
|
}
|
|
if !recRes.RequiresClarifying {
|
|
t.Fatal("expected RequiresClarifying from recognizer")
|
|
}
|
|
if recRes.Branch == intent.BranchAmbiguousFallback {
|
|
t.Fatalf("missing reject_reason should not be AMBIGUOUS_FALLBACK before engine, got %s", recRes.Branch)
|
|
}
|
|
|
|
userCtx := &coordinator.UserProjectContext{
|
|
User: coordinator.UserInfo{ID: "user_102", Name: "李审核", Role: "reviewer", ProjectRole: "reviewer"},
|
|
Project: coordinator.ProjectInfo{
|
|
Name: "智能内窥镜项目",
|
|
CurrentStage: bizdev.StageV05_Feasibility,
|
|
},
|
|
BlackboardFacts: map[string]string{},
|
|
}
|
|
|
|
res, err := engine.ProcessIntent(context.Background(), recRes, userCtx)
|
|
if err != nil {
|
|
t.Fatalf("ProcessIntent failed: %v", err)
|
|
}
|
|
if res.Status != coordinator.StatusClarificationRequired {
|
|
t.Fatalf("expected CLARIFICATION_REQUIRED, got %s", res.Status)
|
|
}
|
|
if !strings.Contains(res.ClarificationPrompt, "驳回理由") {
|
|
t.Fatalf("expected clarification about reject reason, got: %s", res.ClarificationPrompt)
|
|
}
|
|
}
|
|
|
|
// TestEngine_ClaimQueryMustNotExecuteWrite 查询认领不得进入写 handler
|
|
func TestEngine_ClaimQueryMustNotExecuteWrite(t *testing.T) {
|
|
rec := intent.NewRecognizer()
|
|
engine := coordinator.NewCoordinatorEngine(nil)
|
|
|
|
ctx := &intent.ContextSnapshot{
|
|
UserDocRole: "viewer",
|
|
DocLifecycleState: "draft",
|
|
ActiveDocID: "doc-001",
|
|
}
|
|
|
|
recRes, err := rec.Recognize(context.Background(), "这份报告谁认领了?", ctx)
|
|
if err != nil {
|
|
t.Fatalf("recognize failed: %v", err)
|
|
}
|
|
if recRes.TopIntent.Intent == intent.IntentDocGovClaim {
|
|
t.Fatal("claim query must not be classified as DOCGOV_CLAIM")
|
|
}
|
|
|
|
userCtx := &coordinator.UserProjectContext{
|
|
User: coordinator.UserInfo{ID: "user_101", Name: "张工", Role: "engineer", ProjectRole: "composer"},
|
|
Project: coordinator.ProjectInfo{Name: "测试项目"},
|
|
BlackboardFacts: map[string]string{},
|
|
}
|
|
|
|
res, err := engine.ProcessIntent(context.Background(), recRes, userCtx)
|
|
if err != nil {
|
|
t.Fatalf("ProcessIntent failed: %v", err)
|
|
}
|
|
if res.Status == coordinator.StatusAccepted && recRes.TopIntent.Intent == intent.IntentDocGovClaim {
|
|
t.Fatal("claim query must not execute write handler")
|
|
}
|
|
if res.Status != coordinator.StatusClarificationRequired {
|
|
t.Fatalf("expected clarification for claim status query, got %s", res.Status)
|
|
}
|
|
}
|