Files
weichen dc29b84cdf feat(ctx): inject cleaned project dialogue into squad and assistant
Add dialoguectx packaging, conflictresolve adjudication with HITL routing,
workspace context/dialogue/ injection (default on), and goose 00071.
2026-09-24 17:04:04 +00:00

92 lines
2.5 KiB
Go

package conflictresolve_test
import (
"context"
"testing"
"time"
"chat-agent-system/internal/conflictresolve"
"chat-agent-system/internal/dialoguectx"
)
func TestAdjudicateBlackboardBeatsDialogue(t *testing.T) {
now := time.Now()
engine := &conflictresolve.Engine{}
verdicts := engine.Adjudicate(context.Background(),
[]dialoguectx.DialogueFact{{
Key: "device_type", Value: "超声", SpeakerName: "张工",
StatedAt: now, Authority: dialoguectx.AuthorityCollabDialogue,
}},
[]conflictresolve.FactClaim{{
Key: "device_type", Value: "眼科OCT", AuthorityRank: conflictresolve.RankBlackboard,
SourceLabel: "blackboard", StatedAt: now.Add(-time.Hour),
}},
)
if len(verdicts) != 1 {
t.Fatalf("want 1 verdict, got %d", len(verdicts))
}
v := verdicts[0]
if v.Winning.Value != "眼科OCT" {
t.Fatalf("blackboard should win, got %s", v.Winning.Value)
}
if v.NeedsHITL {
t.Fatal("clear authority gap should not need HITL")
}
}
func TestAdjudicateAmbiguousNeedsHITL(t *testing.T) {
now := time.Now()
engine := &conflictresolve.Engine{}
verdicts := engine.Adjudicate(context.Background(),
[]dialoguectx.DialogueFact{
{Key: "budget", Value: "一千万", SpeakerName: "张工", StatedAt: now},
{Key: "budget", Value: "两千万", SpeakerName: "李工", StatedAt: now.Add(5 * time.Minute)},
},
nil,
)
if len(verdicts) != 1 {
t.Fatalf("want 1 verdict, got %d", len(verdicts))
}
if !verdicts[0].NeedsHITL {
t.Fatalf("expected HITL for ambiguous same-rank, got %#v", verdicts[0])
}
if verdicts[0].HITLRoute != conflictresolve.RouteTriggerUser {
t.Fatalf("expected trigger_user route, got %s", verdicts[0].HITLRoute)
}
}
func TestCardLimitAutoAdjudicates(t *testing.T) {
verdicts := make([]conflictresolve.Verdict, 0, 5)
for i := 0; i < 5; i++ {
verdicts = append(verdicts, conflictresolve.Verdict{
FactKey: "k", NeedsHITL: true, CardEligible: true,
Resolution: conflictresolve.ResolutionNeedsConfirm,
Winning: conflictresolve.FactClaim{Value: "v"},
})
}
out := conflictresolve.ApplyCardLimit(verdicts)
cards := 0
autos := 0
for _, v := range out {
if v.NeedsHITL {
cards++
}
if v.Resolution == conflictresolve.ResolutionCardLimitAuto {
autos++
}
}
if cards != conflictresolve.MaxCardsPerTask {
t.Fatalf("want %d cards, got %d", conflictresolve.MaxCardsPerTask, cards)
}
if autos != 2 {
t.Fatalf("want 2 auto, got %d", autos)
}
}
func TestRenderConfirmationsMD(t *testing.T) {
md := conflictresolve.RenderConfirmationsMD(nil, time.Now())
if md == "" {
t.Fatal("empty md")
}
}