Keep WORKFLOW_SCOPE_MODE=strict as the default so cross-workflow mentions stay blocked until weighted mode is turned on. Co-authored-by: Cursor <cursoragent@cursor.com>
123 lines
3.8 KiB
Go
123 lines
3.8 KiB
Go
package workflowscope
|
|
|
|
import "testing"
|
|
|
|
func TestRelationWeightBands(t *testing.T) {
|
|
if got := RelationWeight("main", "main"); got != WeightSame {
|
|
t.Fatalf("same=%v", got)
|
|
}
|
|
if got := RelationWeight("main", ""); got != WeightUnknown {
|
|
t.Fatalf("unknown=%v", got)
|
|
}
|
|
if got := RelationWeight("main", "product_manager"); got != WeightAdjacent {
|
|
t.Fatalf("adjacent=%v", got)
|
|
}
|
|
if got := RelationWeight("main", "rdev"); got != WeightSameDomain {
|
|
t.Fatalf("far medical=%v", got)
|
|
}
|
|
if got := RelationWeight("main", "software_bootstrap"); got != WeightCrossDomain {
|
|
t.Fatalf("cross domain=%v", got)
|
|
}
|
|
if got := RelationWeight("", "rdev"); got != WeightSame {
|
|
t.Fatalf("no active must not penalize, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestDecideWeightedInScopeBeatsCrossName(t *testing.T) {
|
|
SetModeForTest(ModeWeighted)
|
|
t.Cleanup(ResetModeForTest)
|
|
|
|
dec := Decide([]Candidate{
|
|
{ID: "bd_research", Label: "调研报告", Owner: "main", Quality: QualityExact},
|
|
{ID: "rd_proposal", Label: "项目建议书", Owner: "rdev", Quality: QualityExact},
|
|
}, "main", ActionWrite)
|
|
if dec.Kind != KindInScope || dec.Winner.ID != "bd_research" {
|
|
t.Fatalf("in-scope exact must win, got %+v", dec)
|
|
}
|
|
}
|
|
|
|
func TestDecideWeightedCrossExactReadAllowed(t *testing.T) {
|
|
SetModeForTest(ModeWeighted)
|
|
t.Cleanup(ResetModeForTest)
|
|
|
|
dec := Decide([]Candidate{
|
|
{ID: "rd_proposal", Label: "项目建议书", Owner: "rdev", Quality: QualityExact},
|
|
}, "main", ActionRead)
|
|
if dec.Kind != KindCrossAllow || dec.Winner.Owner != "rdev" {
|
|
t.Fatalf("read cross exact want allow, got %+v", dec)
|
|
}
|
|
|
|
write := Decide([]Candidate{
|
|
{ID: "rd_proposal", Label: "项目建议书", Owner: "rdev", Quality: QualityExact},
|
|
}, "main", ActionWrite)
|
|
if write.Kind != KindCrossBlock {
|
|
t.Fatalf("write cross exact want block, got %+v", write)
|
|
}
|
|
}
|
|
|
|
func TestDecideFuzzyCrossNeverWins(t *testing.T) {
|
|
SetModeForTest(ModeWeighted)
|
|
t.Cleanup(ResetModeForTest)
|
|
|
|
dec := Decide([]Candidate{
|
|
{ID: "rd_proposal", Label: "项目建议书", Owner: "rdev", Quality: 0.4},
|
|
}, "main", ActionRead)
|
|
if dec.Kind != KindNone {
|
|
t.Fatalf("fuzzy cross must not win, got %+v", dec)
|
|
}
|
|
}
|
|
|
|
func TestDecideEmptyActiveDoesNotFilter(t *testing.T) {
|
|
SetModeForTest(ModeWeighted)
|
|
t.Cleanup(ResetModeForTest)
|
|
|
|
dec := Decide([]Candidate{
|
|
{ID: "rd_proposal", Label: "项目建议书", Owner: "rdev", Quality: QualityExact},
|
|
}, "", ActionWrite)
|
|
if dec.Kind != KindInScope || dec.Winner.ID != "rd_proposal" {
|
|
t.Fatalf("empty active must pass through, got %+v", dec)
|
|
}
|
|
}
|
|
|
|
func TestDecideStrictKeepsTwoStageBlock(t *testing.T) {
|
|
SetModeForTest(ModeStrict)
|
|
t.Cleanup(ResetModeForTest)
|
|
|
|
dec := Decide([]Candidate{
|
|
{ID: "bd_research", Label: "调研报告", Owner: "main", Quality: 0.4},
|
|
{ID: "rd_proposal", Label: "项目建议书", Owner: "rdev", Quality: QualityExact},
|
|
}, "main", ActionRead)
|
|
if dec.Kind != KindInScope || dec.Winner.ID != "bd_research" {
|
|
t.Fatalf("strict prefers any in-scope hit, got %+v", dec)
|
|
}
|
|
|
|
onlyCross := Decide([]Candidate{
|
|
{ID: "rd_proposal", Label: "项目建议书", Owner: "rdev", Quality: QualityExact},
|
|
}, "main", ActionRead)
|
|
if onlyCross.Kind != KindCrossBlock {
|
|
t.Fatalf("strict cross exact must block even for read, got %+v", onlyCross)
|
|
}
|
|
}
|
|
|
|
func TestParseModeFailSafe(t *testing.T) {
|
|
if parseMode("nope") != ModeStrict {
|
|
t.Fatal("unknown mode must fall back to strict")
|
|
}
|
|
if parseMode("weighted") != ModeWeighted {
|
|
t.Fatal("weighted")
|
|
}
|
|
}
|
|
|
|
func TestContainmentQualityBands(t *testing.T) {
|
|
if ContainmentQuality("调研报告", "调研报告") != QualityExact {
|
|
t.Fatal("exact")
|
|
}
|
|
if ContainmentQuality("用户初始需求表", "用户初始需求收集表") != QualityNormalized {
|
|
t.Fatal("normalized")
|
|
}
|
|
fuzzy := ContainmentQuality("调研", "技术与市场调研报告")
|
|
if fuzzy <= 0 || fuzzy >= MinCrossQuality {
|
|
t.Fatalf("fuzzy=%v must stay below cross threshold", fuzzy)
|
|
}
|
|
}
|